nodePath.cxx 256 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781
  1. // Filename: nodePath.cxx
  2. // Created by: drose (25Feb02)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://etc.cmu.edu/panda3d/docs/license/ .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. #include "nodePath.h"
  19. #include "nodePathCollection.h"
  20. #include "findApproxPath.h"
  21. #include "findApproxLevelEntry.h"
  22. #include "internalNameCollection.h"
  23. #include "config_pgraph.h"
  24. #include "colorAttrib.h"
  25. #include "colorScaleAttrib.h"
  26. #include "cullBinAttrib.h"
  27. #include "textureAttrib.h"
  28. #include "texMatrixAttrib.h"
  29. #include "texGenAttrib.h"
  30. #include "materialAttrib.h"
  31. #include "materialCollection.h"
  32. #include "lightAttrib.h"
  33. #include "clipPlaneAttrib.h"
  34. #include "polylightEffect.h"
  35. #include "fogAttrib.h"
  36. #include "renderModeAttrib.h"
  37. #include "cullFaceAttrib.h"
  38. #include "alphaTestAttrib.h"
  39. #include "depthTestAttrib.h"
  40. #include "depthWriteAttrib.h"
  41. #include "shaderAttrib.h"
  42. #include "billboardEffect.h"
  43. #include "compassEffect.h"
  44. #include "showBoundsEffect.h"
  45. #include "transparencyAttrib.h"
  46. #include "antialiasAttrib.h"
  47. #include "audioVolumeAttrib.h"
  48. #include "texProjectorEffect.h"
  49. #include "texturePool.h"
  50. #include "planeNode.h"
  51. #include "lensNode.h"
  52. #include "materialPool.h"
  53. #include "look_at.h"
  54. #include "plist.h"
  55. #include "boundingSphere.h"
  56. #include "geomNode.h"
  57. #include "sceneGraphAnalyzer.h"
  58. #include "sceneGraphReducer.h"
  59. #include "textureCollection.h"
  60. #include "textureStageCollection.h"
  61. #include "globPattern.h"
  62. #include "shader.h"
  63. #include "shaderInput.h"
  64. #include "config_gobj.h"
  65. #include "bamFile.h"
  66. #include "preparedGraphicsObjects.h"
  67. #include "dcast.h"
  68. // stack seems to overflow on Intel C++ at 7000. If we need more than
  69. // 7000, need to increase stack size.
  70. int NodePath::_max_search_depth = 7000;
  71. TypeHandle NodePath::_type_handle;
  72. ////////////////////////////////////////////////////////////////////
  73. // Function: NodePath::get_num_nodes
  74. // Access: Published
  75. // Description: Returns the number of nodes in the path.
  76. ////////////////////////////////////////////////////////////////////
  77. int NodePath::
  78. get_num_nodes(Thread *current_thread) const {
  79. if (is_empty()) {
  80. return 0;
  81. }
  82. int pipeline_stage = current_thread->get_pipeline_stage();
  83. return _head->get_length(pipeline_stage, current_thread);
  84. }
  85. ////////////////////////////////////////////////////////////////////
  86. // Function: NodePath::get_node
  87. // Access: Published
  88. // Description: Returns the nth node of the path, where 0 is the
  89. // referenced (bottom) node and get_num_nodes() - 1 is
  90. // the top node. This requires iterating through the
  91. // path.
  92. //
  93. // Also see node(), which is a convenience function to
  94. // return the same thing as get_node(0) (since the
  95. // bottom node is the most important node in the
  96. // NodePath, and is the one most frequently referenced).
  97. ////////////////////////////////////////////////////////////////////
  98. PandaNode *NodePath::
  99. get_node(int index, Thread *current_thread) const {
  100. nassertr(index >= 0 && index < get_num_nodes(), NULL);
  101. int pipeline_stage = current_thread->get_pipeline_stage();
  102. NodePathComponent *comp = _head;
  103. while (index > 0) {
  104. // If this assertion fails, the index was out of range; the
  105. // component's length must have been invalid.
  106. nassertr(comp != (NodePathComponent *)NULL, NULL);
  107. comp = comp->get_next(pipeline_stage, current_thread);
  108. index--;
  109. }
  110. // If this assertion fails, the index was out of range; the
  111. // component's length must have been invalid.
  112. nassertr(comp != (NodePathComponent *)NULL, NULL);
  113. return comp->get_node();
  114. }
  115. ////////////////////////////////////////////////////////////////////
  116. // Function: NodePath::get_top
  117. // Access: Published
  118. // Description: Returns a singleton NodePath that represents the top
  119. // of the path, or empty NodePath if this path is empty.
  120. ////////////////////////////////////////////////////////////////////
  121. NodePath NodePath::
  122. get_top(Thread *current_thread) const {
  123. if (is_empty()) {
  124. return *this;
  125. }
  126. int pipeline_stage = current_thread->get_pipeline_stage();
  127. NodePathComponent *comp = _head;
  128. while (!comp->is_top_node(pipeline_stage, current_thread)) {
  129. comp = comp->get_next(pipeline_stage, current_thread);
  130. nassertr(comp != (NodePathComponent *)NULL, NULL);
  131. }
  132. NodePath top;
  133. top._head = comp;
  134. return top;
  135. }
  136. ////////////////////////////////////////////////////////////////////
  137. // Function: NodePath::get_children
  138. // Access: Published
  139. // Description: Returns the set of all child nodes of the referenced
  140. // node.
  141. ////////////////////////////////////////////////////////////////////
  142. NodePathCollection NodePath::
  143. get_children(Thread *current_thread) const {
  144. NodePathCollection result;
  145. nassertr_always(!is_empty(), result);
  146. PandaNode *bottom_node = node();
  147. int pipeline_stage = current_thread->get_pipeline_stage();
  148. PandaNode::Children cr = bottom_node->get_children();
  149. int num_children = cr.get_num_children();
  150. for (int i = 0; i < num_children; i++) {
  151. NodePath child;
  152. child._head = PandaNode::get_component(_head, cr.get_child(i),
  153. pipeline_stage, current_thread);
  154. result.add_path(child);
  155. }
  156. return result;
  157. }
  158. ////////////////////////////////////////////////////////////////////
  159. // Function: NodePath::get_stashed_children
  160. // Access: Published
  161. // Description: Returns the set of all child nodes of the referenced
  162. // node that have been stashed. These children are not
  163. // normally visible on the node, and do not appear in
  164. // the list returned by get_children().
  165. ////////////////////////////////////////////////////////////////////
  166. NodePathCollection NodePath::
  167. get_stashed_children(Thread *current_thread) const {
  168. NodePathCollection result;
  169. nassertr_always(!is_empty(), result);
  170. PandaNode *bottom_node = node();
  171. int pipeline_stage = current_thread->get_pipeline_stage();
  172. int num_stashed = bottom_node->get_num_stashed();
  173. for (int i = 0; i < num_stashed; i++) {
  174. NodePath stashed;
  175. stashed._head = PandaNode::get_component(_head, bottom_node->get_stashed(i),
  176. pipeline_stage, current_thread);
  177. result.add_path(stashed);
  178. }
  179. return result;
  180. }
  181. ////////////////////////////////////////////////////////////////////
  182. // Function: NodePath::get_sort
  183. // Access: Published
  184. // Description: Returns the sort value of the referenced node within
  185. // its parent; that is, the sort number passed on the
  186. // last reparenting operation for this node. This will
  187. // control the position of the node within its parent's
  188. // list of children.
  189. ////////////////////////////////////////////////////////////////////
  190. int NodePath::
  191. get_sort(Thread *current_thread) const {
  192. if (!has_parent()) {
  193. return 0;
  194. }
  195. int pipeline_stage = current_thread->get_pipeline_stage();
  196. PandaNode *parent = _head->get_next(pipeline_stage, current_thread)->get_node();
  197. PandaNode *child = node();
  198. nassertr(parent != (PandaNode *)NULL && child != (PandaNode *)NULL, 0);
  199. int child_index = parent->find_child(child);
  200. if (child_index != -1) {
  201. return parent->get_child_sort(child_index);
  202. }
  203. child_index = parent->find_stashed(child);
  204. if (child_index != -1) {
  205. return parent->get_stashed_sort(child_index);
  206. }
  207. nassertr(false, 0);
  208. return 0;
  209. }
  210. ////////////////////////////////////////////////////////////////////
  211. // Function: NodePath::find
  212. // Access: Published
  213. // Description: Searches for a node below the referenced node that
  214. // matches the indicated string. Returns the shortest
  215. // match found, if any, or an empty NodePath if no match
  216. // can be found.
  217. ////////////////////////////////////////////////////////////////////
  218. NodePath NodePath::
  219. find(const string &path) const {
  220. nassertr_always(!is_empty(), fail());
  221. NodePathCollection col;
  222. find_matches(col, path, 1);
  223. if (col.is_empty()) {
  224. return NodePath::not_found();
  225. }
  226. return col.get_path(0);
  227. }
  228. ////////////////////////////////////////////////////////////////////
  229. // Function: NodePath::find_path_to
  230. // Access: Published
  231. // Description: Searches for the indicated node below this node and
  232. // returns the shortest NodePath that connects them.
  233. ////////////////////////////////////////////////////////////////////
  234. NodePath NodePath::
  235. find_path_to(PandaNode *node) const {
  236. nassertr_always(!is_empty(), fail());
  237. nassertr(node != (PandaNode *)NULL, fail());
  238. NodePathCollection col;
  239. FindApproxPath approx_path;
  240. approx_path.add_match_many(0);
  241. approx_path.add_match_pointer(node, 0);
  242. find_matches(col, approx_path, 1);
  243. if (col.is_empty()) {
  244. return NodePath::not_found();
  245. }
  246. return col.get_path(0);
  247. }
  248. ////////////////////////////////////////////////////////////////////
  249. // Function: NodePath::find_all_matches
  250. // Access: Published
  251. // Description: Returns the complete set of all NodePaths that begin
  252. // with this NodePath and can be extended by
  253. // path. The shortest paths will be listed
  254. // first.
  255. ////////////////////////////////////////////////////////////////////
  256. NodePathCollection NodePath::
  257. find_all_matches(const string &path) const {
  258. NodePathCollection col;
  259. nassertr_always(!is_empty(), col);
  260. nassertr(verify_complete(), col);
  261. find_matches(col, path, -1);
  262. return col;
  263. }
  264. ////////////////////////////////////////////////////////////////////
  265. // Function: NodePath::find_all_paths_to
  266. // Access: Published
  267. // Description: Returns the set of all NodePaths that extend from
  268. // this NodePath down to the indicated node. The
  269. // shortest paths will be listed first.
  270. ////////////////////////////////////////////////////////////////////
  271. NodePathCollection NodePath::
  272. find_all_paths_to(PandaNode *node) const {
  273. NodePathCollection col;
  274. nassertr_always(!is_empty(), col);
  275. nassertr(verify_complete(), col);
  276. nassertr(node != (PandaNode *)NULL, col);
  277. FindApproxPath approx_path;
  278. approx_path.add_match_many(0);
  279. approx_path.add_match_pointer(node, 0);
  280. find_matches(col, approx_path, -1);
  281. return col;
  282. }
  283. ////////////////////////////////////////////////////////////////////
  284. // Function: NodePath::reparent_to
  285. // Access: Published
  286. // Description: Removes the referenced node of the NodePath from its
  287. // current parent and attaches it to the referenced node
  288. // of the indicated NodePath.
  289. //
  290. // If the destination NodePath is empty, this is the
  291. // same thing as detach_node().
  292. ////////////////////////////////////////////////////////////////////
  293. void NodePath::
  294. reparent_to(const NodePath &other, int sort, Thread *current_thread) {
  295. nassertv(verify_complete());
  296. nassertv(other.verify_complete());
  297. nassertv_always(!is_empty());
  298. nassertv(other._error_type == ET_ok);
  299. // Reparenting implicitly resets the delta vector.
  300. node()->reset_prev_transform();
  301. int pipeline_stage = current_thread->get_pipeline_stage();
  302. bool reparented = PandaNode::reparent(other._head, _head, sort, false,
  303. pipeline_stage, current_thread);
  304. nassertv(reparented);
  305. }
  306. ////////////////////////////////////////////////////////////////////
  307. // Function: NodePath::wrt_reparent_to
  308. // Access: Published
  309. // Description: This functions identically to reparent_to(), except
  310. // the transform on this node is also adjusted so that
  311. // the node remains in the same place in world
  312. // coordinates, even if it is reparented into a
  313. // different coordinate system.
  314. ////////////////////////////////////////////////////////////////////
  315. void NodePath::
  316. wrt_reparent_to(const NodePath &other, int sort, Thread *current_thread) {
  317. nassertv(verify_complete(current_thread));
  318. nassertv(other.verify_complete(current_thread));
  319. nassertv_always(!is_empty());
  320. nassertv(other._error_type == ET_ok);
  321. if (get_transform(current_thread) == get_prev_transform(current_thread)) {
  322. set_transform(get_transform(other, current_thread), current_thread);
  323. node()->reset_prev_transform(current_thread);
  324. } else {
  325. set_transform(get_transform(other, current_thread), current_thread);
  326. set_prev_transform(get_prev_transform(other, current_thread), current_thread);
  327. }
  328. reparent_to(other, sort, current_thread);
  329. }
  330. ////////////////////////////////////////////////////////////////////
  331. // Function: NodePath::instance_to
  332. // Access: Published
  333. // Description: Adds the referenced node of the NodePath as a child
  334. // of the referenced node of the indicated other
  335. // NodePath. Any other parent-child relations of the
  336. // node are unchanged; in particular, the node is not
  337. // removed from its existing parent, if any.
  338. //
  339. // If the node already had an existing parent, this
  340. // method will create a new instance of the node within
  341. // the scene graph.
  342. //
  343. // This does not change the NodePath itself, but does
  344. // return a new NodePath that reflects the new instance
  345. // node.
  346. //
  347. // If the destination NodePath is empty, this creates a
  348. // new instance which is not yet parented to any node.
  349. // A new instance of this sort cannot easily be
  350. // differentiated from other similar instances, but it
  351. // is nevertheless a different instance and it will
  352. // return a different get_id() value.
  353. ////////////////////////////////////////////////////////////////////
  354. NodePath NodePath::
  355. instance_to(const NodePath &other, int sort, Thread *current_thread) const {
  356. nassertr(verify_complete(), NodePath::fail());
  357. nassertr(other.verify_complete(), NodePath::fail());
  358. nassertr_always(!is_empty(), NodePath::fail());
  359. nassertr(other._error_type == ET_ok, NodePath::fail());
  360. NodePath new_instance;
  361. // First, we'll attach to NULL, to guarantee we get a brand new
  362. // instance.
  363. int pipeline_stage = current_thread->get_pipeline_stage();
  364. new_instance._head = PandaNode::attach(NULL, node(), sort, pipeline_stage,
  365. current_thread);
  366. // Now, we'll reparent the new instance to the target node.
  367. bool reparented = PandaNode::reparent(other._head, new_instance._head,
  368. sort, false, pipeline_stage,
  369. current_thread);
  370. nassertr(reparented, new_instance);
  371. // instance_to() doesn't reset the velocity delta, unlike most of
  372. // the other reparenting operations. The reasoning is that
  373. // instance_to() is not necessarily a reparenting operation, since
  374. // it doesn't change the original instance.
  375. return new_instance;
  376. }
  377. ////////////////////////////////////////////////////////////////////
  378. // Function: NodePath::instance_under_node
  379. // Access: Published
  380. // Description: Behaves like instance_to(), but implicitly creates a
  381. // new node to instance the geometry under, and returns a
  382. // NodePath to that new node. This allows the
  383. // programmer to set a unique state and/or transform on
  384. // this instance.
  385. ////////////////////////////////////////////////////////////////////
  386. NodePath NodePath::
  387. instance_under_node(const NodePath &other, const string &name, int sort,
  388. Thread *current_thread) const {
  389. NodePath new_node = other.attach_new_node(name, sort, current_thread);
  390. NodePath instance = instance_to(new_node, 0, current_thread);
  391. if (instance.is_empty()) {
  392. new_node.remove_node(current_thread);
  393. return instance;
  394. }
  395. return new_node;
  396. }
  397. ////////////////////////////////////////////////////////////////////
  398. // Function: NodePath::copy_to
  399. // Access: Published
  400. // Description: Functions like instance_to(), except a deep
  401. // copy is made of the referenced node and all of its
  402. // descendents, which is then parented to the indicated
  403. // node. A NodePath to the newly created copy is
  404. // returned.
  405. ////////////////////////////////////////////////////////////////////
  406. NodePath NodePath::
  407. copy_to(const NodePath &other, int sort, Thread *current_thread) const {
  408. nassertr(verify_complete(current_thread), fail());
  409. nassertr(other.verify_complete(current_thread), fail());
  410. nassertr_always(!is_empty(), fail());
  411. nassertr(other._error_type == ET_ok, fail());
  412. PandaNode *source_node = node();
  413. PT(PandaNode) copy_node = source_node->copy_subgraph(current_thread);
  414. nassertr(copy_node != (PandaNode *)NULL, fail());
  415. copy_node->reset_prev_transform(current_thread);
  416. return other.attach_new_node(copy_node, sort, current_thread);
  417. }
  418. ////////////////////////////////////////////////////////////////////
  419. // Function: NodePath::attach_new_node
  420. // Access: Published
  421. // Description: Attaches a new node, with or without existing
  422. // parents, to the scene graph below the referenced node
  423. // of this NodePath. This is the preferred way to add
  424. // nodes to the graph.
  425. //
  426. // If the node was already a child of the parent, this
  427. // returns a NodePath to the existing child.
  428. //
  429. // This does *not* automatically extend the current
  430. // NodePath to reflect the attachment; however, a
  431. // NodePath that does reflect this extension is
  432. // returned.
  433. ////////////////////////////////////////////////////////////////////
  434. NodePath NodePath::
  435. attach_new_node(PandaNode *node, int sort, Thread *current_thread) const {
  436. nassertr(verify_complete(current_thread), NodePath::fail());
  437. nassertr(_error_type == ET_ok, NodePath::fail());
  438. nassertr(node != (PandaNode *)NULL, NodePath::fail());
  439. NodePath new_path(*this);
  440. int pipeline_stage = current_thread->get_pipeline_stage();
  441. new_path._head = PandaNode::attach(_head, node, sort, pipeline_stage,
  442. current_thread);
  443. return new_path;
  444. }
  445. ////////////////////////////////////////////////////////////////////
  446. // Function: NodePath::remove_node
  447. // Access: Published
  448. // Description: Disconnects the referenced node from the scene graph.
  449. // This will also delete the node if there are no other
  450. // pointers to it.
  451. //
  452. // Normally, this should be called only when you are
  453. // really done with the node. If you want to remove a
  454. // node from the scene graph but keep it around for
  455. // later, you should probably use detach_node() instead.
  456. //
  457. // In practice, the only difference between
  458. // remove_node() and detach_node() is that remove_node()
  459. // also resets the NodePath to empty, which will cause
  460. // the node to be deleted immediately if there are no
  461. // other references. On the other hand, detach_node()
  462. // leaves the NodePath referencing the node, which will
  463. // keep at least one reference to the node for as long
  464. // as the NodePath exists.
  465. ////////////////////////////////////////////////////////////////////
  466. void NodePath::
  467. remove_node(Thread *current_thread) {
  468. nassertv(_error_type != ET_not_found);
  469. // If we have no parents, remove_node() is just a do-nothing
  470. // operation; if we have no nodes, maybe we were already removed.
  471. // In either case, quietly do nothing except to ensure the
  472. // NodePath is clear.
  473. if (!is_empty() && !is_singleton(current_thread)) {
  474. node()->reset_prev_transform(current_thread);
  475. int pipeline_stage = current_thread->get_pipeline_stage();
  476. PandaNode::detach(_head, pipeline_stage, current_thread);
  477. }
  478. if (is_empty() || _head->has_key()) {
  479. // Preserve the key we had on the node before we removed it.
  480. int key = get_key();
  481. (*this) = NodePath::removed();
  482. _backup_key = key;
  483. } else {
  484. // We didn't have a key; just clear the NodePath.
  485. (*this) = NodePath::removed();
  486. }
  487. }
  488. ////////////////////////////////////////////////////////////////////
  489. // Function: NodePath::detach_node
  490. // Access: Published
  491. // Description: Disconnects the referenced node from its parent, but
  492. // does not immediately delete it. The NodePath retains
  493. // a pointer to the node, and becomes a singleton
  494. // NodePath.
  495. //
  496. // This should be called to detach a node from the scene
  497. // graph, with the option of reattaching it later to the
  498. // same parent or to a different parent.
  499. //
  500. // In practice, the only difference between
  501. // remove_node() and detach_node() is that remove_node()
  502. // also resets the NodePath to empty, which will cause
  503. // the node to be deleted immediately if there are no
  504. // other references. On the other hand, detach_node()
  505. // leaves the NodePath referencing the node, which will
  506. // keep at least one reference to the node for as long
  507. // as the NodePath exists.
  508. ////////////////////////////////////////////////////////////////////
  509. void NodePath::
  510. detach_node(Thread *current_thread) {
  511. nassertv(_error_type != ET_not_found);
  512. if (!is_empty() && !is_singleton()) {
  513. node()->reset_prev_transform();
  514. int pipeline_stage = current_thread->get_pipeline_stage();
  515. PandaNode::detach(_head, pipeline_stage, current_thread);
  516. }
  517. }
  518. ////////////////////////////////////////////////////////////////////
  519. // Function: NodePath::output
  520. // Access: Published
  521. // Description: Writes a sensible description of the NodePath to the
  522. // indicated output stream.
  523. ////////////////////////////////////////////////////////////////////
  524. void NodePath::
  525. output(ostream &out) const {
  526. switch (_error_type) {
  527. case ET_not_found:
  528. out << "**not found**";
  529. return;
  530. case ET_removed:
  531. out << "**removed**";
  532. return;
  533. case ET_fail:
  534. out << "**error**";
  535. return;
  536. default:
  537. break;
  538. }
  539. if (_head == (NodePathComponent *)NULL) {
  540. out << "(empty)";
  541. } else {
  542. _head->output(out);
  543. }
  544. }
  545. ////////////////////////////////////////////////////////////////////
  546. // Function: NodePath::get_state
  547. // Access: Published
  548. // Description: Returns the complete state object set on this node.
  549. ////////////////////////////////////////////////////////////////////
  550. const RenderState *NodePath::
  551. get_state(Thread *current_thread) const {
  552. // This method is declared non-inline to avoid a compiler bug in
  553. // gcc-3.4 and gcc-4.0.
  554. nassertr_always(!is_empty(), RenderState::make_empty());
  555. return node()->get_state(current_thread);
  556. }
  557. ////////////////////////////////////////////////////////////////////
  558. // Function: NodePath::get_state
  559. // Access: Published
  560. // Description: Returns the state changes that must be made to
  561. // transition to the render state of this node from the
  562. // render state of the other node.
  563. ////////////////////////////////////////////////////////////////////
  564. CPT(RenderState) NodePath::
  565. get_state(const NodePath &other, Thread *current_thread) const {
  566. nassertr(_error_type == ET_ok && other._error_type == ET_ok, RenderState::make_empty());
  567. if (other.is_empty()) {
  568. return get_net_state(current_thread);
  569. }
  570. if (is_empty()) {
  571. return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty());
  572. }
  573. nassertr(verify_complete(current_thread), RenderState::make_empty());
  574. nassertr(other.verify_complete(current_thread), RenderState::make_empty());
  575. int a_count, b_count;
  576. if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
  577. if (allow_unrelated_wrt) {
  578. pgraph_cat.debug()
  579. << *this << " is not related to " << other << "\n";
  580. } else {
  581. pgraph_cat.error()
  582. << *this << " is not related to " << other << "\n";
  583. nassertr(false, RenderState::make_empty());
  584. }
  585. }
  586. CPT(RenderState) a_state = r_get_partial_state(_head, a_count, current_thread);
  587. CPT(RenderState) b_state = r_get_partial_state(other._head, b_count, current_thread);
  588. return b_state->invert_compose(a_state);
  589. }
  590. ////////////////////////////////////////////////////////////////////
  591. // Function: NodePath::set_state
  592. // Access: Published
  593. // Description: Sets the state object on this node, relative to
  594. // the other node. This computes a new state object
  595. // that will have the indicated value when seen from the
  596. // other node.
  597. ////////////////////////////////////////////////////////////////////
  598. void NodePath::
  599. set_state(const NodePath &other, const RenderState *state,
  600. Thread *current_thread) {
  601. nassertv(_error_type == ET_ok && other._error_type == ET_ok);
  602. nassertv_always(!is_empty());
  603. // First, we perform a wrt to the parent, to get the conversion.
  604. CPT(RenderState) rel_state;
  605. if (has_parent()) {
  606. rel_state = other.get_state(get_parent(current_thread), current_thread);
  607. } else {
  608. rel_state = other.get_state(NodePath(), current_thread);
  609. }
  610. CPT(RenderState) new_state = rel_state->compose(state);
  611. set_state(new_state, current_thread);
  612. }
  613. ////////////////////////////////////////////////////////////////////
  614. // Function: NodePath::get_transform
  615. // Access: Published
  616. // Description: Returns the complete transform object set on this node.
  617. ////////////////////////////////////////////////////////////////////
  618. const TransformState *NodePath::
  619. get_transform(Thread *current_thread) const {
  620. // This method is declared non-inline to avoid a compiler bug in
  621. // gcc-3.4 and gcc-4.0.
  622. nassertr_always(!is_empty(), TransformState::make_identity());
  623. return node()->get_transform(current_thread);
  624. }
  625. ////////////////////////////////////////////////////////////////////
  626. // Function: NodePath::get_transform
  627. // Access: Published
  628. // Description: Returns the relative transform to this node from the
  629. // other node; i.e. the transformation of this node
  630. // as seen from the other node.
  631. ////////////////////////////////////////////////////////////////////
  632. CPT(TransformState) NodePath::
  633. get_transform(const NodePath &other, Thread *current_thread) const {
  634. nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
  635. if (other.is_empty()) {
  636. return get_net_transform(current_thread);
  637. }
  638. if (is_empty()) {
  639. return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity());
  640. }
  641. nassertr(verify_complete(current_thread), TransformState::make_identity());
  642. nassertr(other.verify_complete(current_thread), TransformState::make_identity());
  643. int a_count, b_count;
  644. if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
  645. if (allow_unrelated_wrt) {
  646. if (pgraph_cat.is_debug()) {
  647. pgraph_cat.debug()
  648. << *this << " is not related to " << other << "\n";
  649. }
  650. } else {
  651. pgraph_cat.error()
  652. << *this << " is not related to " << other << "\n";
  653. nassertr(false, TransformState::make_identity());
  654. }
  655. }
  656. CPT(TransformState) a_transform, b_transform;
  657. a_transform = r_get_partial_transform(_head, a_count, current_thread);
  658. if (a_transform != (TransformState *)NULL) {
  659. b_transform = r_get_partial_transform(other._head, b_count, current_thread);
  660. }
  661. if (b_transform == (TransformState *)NULL) {
  662. // If either path involved a node with a net_transform
  663. // RenderEffect applied, we have to go all the way up to the root
  664. // to get the right answer.
  665. a_transform = r_get_net_transform(_head, current_thread);
  666. b_transform = r_get_net_transform(other._head, current_thread);
  667. }
  668. return b_transform->invert_compose(a_transform);
  669. }
  670. ////////////////////////////////////////////////////////////////////
  671. // Function: NodePath::set_transform
  672. // Access: Published
  673. // Description: Sets the transform object on this node, relative to
  674. // the other node. This computes a new transform object
  675. // that will have the indicated value when seen from the
  676. // other node.
  677. ////////////////////////////////////////////////////////////////////
  678. void NodePath::
  679. set_transform(const NodePath &other, const TransformState *transform,
  680. Thread *current_thread) {
  681. nassertv(_error_type == ET_ok && other._error_type == ET_ok);
  682. nassertv_always(!is_empty());
  683. // First, we perform a wrt to the parent, to get the conversion.
  684. CPT(TransformState) rel_trans;
  685. if (has_parent()) {
  686. rel_trans = other.get_transform(get_parent(current_thread), current_thread);
  687. } else {
  688. rel_trans = other.get_transform(NodePath(), current_thread);
  689. }
  690. CPT(TransformState) new_trans = rel_trans->compose(transform);
  691. set_transform(new_trans, current_thread);
  692. }
  693. ////////////////////////////////////////////////////////////////////
  694. // Function: NodePath::get_prev_transform
  695. // Access: Published
  696. // Description: Returns the transform that has been set as this
  697. // node's "previous" position. See
  698. // set_prev_transform().
  699. ////////////////////////////////////////////////////////////////////
  700. const TransformState *NodePath::
  701. get_prev_transform(Thread *current_thread) const {
  702. // This method is declared non-inline to avoid a compiler bug in
  703. // gcc-3.4 and gcc-4.0.
  704. nassertr_always(!is_empty(), TransformState::make_identity());
  705. return node()->get_prev_transform(current_thread);
  706. }
  707. ////////////////////////////////////////////////////////////////////
  708. // Function: NodePath::get_prev_transform
  709. // Access: Published
  710. // Description: Returns the relative "previous" transform to this
  711. // node from the other node; i.e. the position of this
  712. // node in the previous frame, as seen by the other node
  713. // in the previous frame.
  714. ////////////////////////////////////////////////////////////////////
  715. CPT(TransformState) NodePath::
  716. get_prev_transform(const NodePath &other, Thread *current_thread) const {
  717. nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
  718. if (other.is_empty()) {
  719. return get_net_prev_transform(current_thread);
  720. }
  721. if (is_empty()) {
  722. return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity());
  723. }
  724. nassertr(verify_complete(current_thread), TransformState::make_identity());
  725. nassertr(other.verify_complete(current_thread), TransformState::make_identity());
  726. int a_count, b_count;
  727. if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) {
  728. if (allow_unrelated_wrt) {
  729. pgraph_cat.debug()
  730. << *this << " is not related to " << other << "\n";
  731. } else {
  732. pgraph_cat.error()
  733. << *this << " is not related to " << other << "\n";
  734. nassertr(false, TransformState::make_identity());
  735. }
  736. }
  737. CPT(TransformState) a_prev_transform = r_get_partial_prev_transform(_head, a_count, current_thread);
  738. CPT(TransformState) b_prev_transform = r_get_partial_prev_transform(other._head, b_count, current_thread);
  739. return b_prev_transform->invert_compose(a_prev_transform);
  740. }
  741. ////////////////////////////////////////////////////////////////////
  742. // Function: NodePath::set_prev_transform
  743. // Access: Published
  744. // Description: Sets the "previous" transform object on this node,
  745. // relative to the other node. This computes a new
  746. // transform object that will have the indicated value
  747. // when seen from the other node.
  748. ////////////////////////////////////////////////////////////////////
  749. void NodePath::
  750. set_prev_transform(const NodePath &other, const TransformState *transform,
  751. Thread *current_thread) {
  752. nassertv(_error_type == ET_ok && other._error_type == ET_ok);
  753. nassertv_always(!is_empty());
  754. // First, we perform a wrt to the parent, to get the conversion.
  755. CPT(TransformState) rel_trans;
  756. if (has_parent(current_thread)) {
  757. rel_trans = other.get_prev_transform(get_parent(current_thread), current_thread);
  758. } else {
  759. rel_trans = other.get_prev_transform(NodePath(), current_thread);
  760. }
  761. CPT(TransformState) new_trans = rel_trans->compose(transform);
  762. set_prev_transform(new_trans, current_thread);
  763. }
  764. ////////////////////////////////////////////////////////////////////
  765. // Function: NodePath::set_pos
  766. // Access: Published
  767. // Description: Sets the translation component of the transform,
  768. // leaving rotation and scale untouched. This also
  769. // resets the node's "previous" position, so that the
  770. // collision system will see the node as having suddenly
  771. // appeared in the new position, without passing any
  772. // points in between.
  773. // See Also: NodePath::set_fluid_pos
  774. ////////////////////////////////////////////////////////////////////
  775. void NodePath::
  776. set_pos(const LVecBase3f &pos) {
  777. nassertv_always(!is_empty());
  778. set_transform(get_transform()->set_pos(pos));
  779. node()->reset_prev_transform();
  780. }
  781. void NodePath::
  782. set_x(float x) {
  783. nassertv_always(!is_empty());
  784. LPoint3f pos = get_pos();
  785. pos[0] = x;
  786. set_pos(pos);
  787. }
  788. void NodePath::
  789. set_y(float y) {
  790. nassertv_always(!is_empty());
  791. LPoint3f pos = get_pos();
  792. pos[1] = y;
  793. set_pos(pos);
  794. }
  795. void NodePath::
  796. set_z(float z) {
  797. nassertv_always(!is_empty());
  798. LPoint3f pos = get_pos();
  799. pos[2] = z;
  800. set_pos(pos);
  801. }
  802. ////////////////////////////////////////////////////////////////////
  803. // Function: NodePath::set_fluid_pos
  804. // Access: Published
  805. // Description: Sets the translation component, without changing the
  806. // "previous" position, so that the collision system
  807. // will see the node as moving fluidly from its previous
  808. // position to its new position.
  809. // See Also: NodePath::set_pos
  810. ////////////////////////////////////////////////////////////////////
  811. void NodePath::
  812. set_fluid_pos(const LVecBase3f &pos) {
  813. nassertv_always(!is_empty());
  814. set_transform(get_transform()->set_pos(pos));
  815. }
  816. void NodePath::
  817. set_fluid_x(float x) {
  818. nassertv_always(!is_empty());
  819. LPoint3f pos = get_pos();
  820. pos[0] = x;
  821. set_fluid_pos(pos);
  822. }
  823. void NodePath::
  824. set_fluid_y(float y) {
  825. nassertv_always(!is_empty());
  826. LPoint3f pos = get_pos();
  827. pos[1] = y;
  828. set_fluid_pos(pos);
  829. }
  830. void NodePath::
  831. set_fluid_z(float z) {
  832. nassertv_always(!is_empty());
  833. LPoint3f pos = get_pos();
  834. pos[2] = z;
  835. set_fluid_pos(pos);
  836. }
  837. ////////////////////////////////////////////////////////////////////
  838. // Function: NodePath::get_pos
  839. // Access: Published
  840. // Description: Retrieves the translation component of the transform.
  841. ////////////////////////////////////////////////////////////////////
  842. LPoint3f NodePath::
  843. get_pos() const {
  844. nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
  845. return get_transform()->get_pos();
  846. }
  847. ////////////////////////////////////////////////////////////////////
  848. // Function: NodePath::get_pos_delta
  849. // Access: Published
  850. // Description: Returns the delta vector from this node's position in
  851. // the previous frame (according to
  852. // set_prev_transform(), typically set via the use of
  853. // set_fluid_pos()) and its position in the current
  854. // frame. This is the vector used to determine
  855. // collisions. Generally, if the node was last
  856. // repositioned via set_pos(), the delta will be zero;
  857. // if it was adjusted via set_fluid_pos(), the delta
  858. // will represent the change from the previous frame's
  859. // position.
  860. ////////////////////////////////////////////////////////////////////
  861. LVector3f NodePath::
  862. get_pos_delta() const {
  863. nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
  864. return get_transform()->get_pos() - get_prev_transform()->get_pos();
  865. }
  866. ////////////////////////////////////////////////////////////////////
  867. // Function: NodePath::set_hpr
  868. // Access: Published
  869. // Description: Sets the rotation component of the transform,
  870. // leaving translation and scale untouched.
  871. ////////////////////////////////////////////////////////////////////
  872. void NodePath::
  873. set_hpr(const LVecBase3f &hpr) {
  874. nassertv_always(!is_empty());
  875. CPT(TransformState) transform = get_transform();
  876. nassertv(transform->has_hpr());
  877. set_transform(transform->set_hpr(hpr));
  878. }
  879. void NodePath::
  880. set_h(float h) {
  881. nassertv_always(!is_empty());
  882. CPT(TransformState) transform = get_transform();
  883. nassertv(transform->has_hpr());
  884. LVecBase3f hpr = transform->get_hpr();
  885. hpr[0] = h;
  886. set_transform(transform->set_hpr(hpr));
  887. }
  888. void NodePath::
  889. set_p(float p) {
  890. nassertv_always(!is_empty());
  891. CPT(TransformState) transform = get_transform();
  892. nassertv(transform->has_hpr());
  893. LVecBase3f hpr = transform->get_hpr();
  894. hpr[1] = p;
  895. set_transform(transform->set_hpr(hpr));
  896. }
  897. void NodePath::
  898. set_r(float r) {
  899. nassertv_always(!is_empty());
  900. CPT(TransformState) transform = get_transform();
  901. nassertv(transform->has_hpr());
  902. LVecBase3f hpr = transform->get_hpr();
  903. hpr[2] = r;
  904. set_transform(transform->set_hpr(hpr));
  905. }
  906. ////////////////////////////////////////////////////////////////////
  907. // Function: NodePath::get_hpr
  908. // Access: Published
  909. // Description: Retrieves the rotation component of the transform.
  910. ////////////////////////////////////////////////////////////////////
  911. LVecBase3f NodePath::
  912. get_hpr() const {
  913. nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
  914. CPT(TransformState) transform = get_transform();
  915. nassertr(transform->has_hpr(), LVecBase3f(0.0f, 0.0f, 0.0f));
  916. return transform->get_hpr();
  917. }
  918. ////////////////////////////////////////////////////////////////////
  919. // Function: NodePath::set_quat
  920. // Access: Published
  921. // Description: Sets the rotation component of the transform,
  922. // leaving translation and scale untouched.
  923. ////////////////////////////////////////////////////////////////////
  924. void NodePath::
  925. set_quat(const LQuaternionf &quat) {
  926. nassertv_always(!is_empty());
  927. CPT(TransformState) transform = get_transform();
  928. set_transform(transform->set_quat(quat));
  929. }
  930. ////////////////////////////////////////////////////////////////////
  931. // Function: NodePath::get_quat
  932. // Access: Published
  933. // Description: Retrieves the rotation component of the transform.
  934. ////////////////////////////////////////////////////////////////////
  935. LQuaternionf NodePath::
  936. get_quat() const {
  937. nassertr_always(!is_empty(), LQuaternionf::ident_quat());
  938. CPT(TransformState) transform = get_transform();
  939. return transform->get_quat();
  940. }
  941. ////////////////////////////////////////////////////////////////////
  942. // Function: NodePath::set_scale
  943. // Access: Published
  944. // Description: Sets the scale component of the transform,
  945. // leaving translation and rotation untouched.
  946. ////////////////////////////////////////////////////////////////////
  947. void NodePath::
  948. set_scale(const LVecBase3f &scale) {
  949. nassertv_always(!is_empty());
  950. CPT(TransformState) transform = get_transform();
  951. set_transform(transform->set_scale(scale));
  952. }
  953. void NodePath::
  954. set_sx(float sx) {
  955. nassertv_always(!is_empty());
  956. CPT(TransformState) transform = get_transform();
  957. LVecBase3f scale = transform->get_scale();
  958. scale[0] = sx;
  959. set_transform(transform->set_scale(scale));
  960. }
  961. void NodePath::
  962. set_sy(float sy) {
  963. nassertv_always(!is_empty());
  964. CPT(TransformState) transform = get_transform();
  965. LVecBase3f scale = transform->get_scale();
  966. scale[1] = sy;
  967. set_transform(transform->set_scale(scale));
  968. }
  969. void NodePath::
  970. set_sz(float sz) {
  971. nassertv_always(!is_empty());
  972. CPT(TransformState) transform = get_transform();
  973. LVecBase3f scale = transform->get_scale();
  974. scale[2] = sz;
  975. set_transform(transform->set_scale(scale));
  976. }
  977. ////////////////////////////////////////////////////////////////////
  978. // Function: NodePath::get_scale
  979. // Access: Published
  980. // Description: Retrieves the scale component of the transform.
  981. ////////////////////////////////////////////////////////////////////
  982. LVecBase3f NodePath::
  983. get_scale() const {
  984. nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
  985. CPT(TransformState) transform = get_transform();
  986. return transform->get_scale();
  987. }
  988. ////////////////////////////////////////////////////////////////////
  989. // Function: NodePath::set_shear
  990. // Access: Published
  991. // Description: Sets the shear component of the transform,
  992. // leaving translation and rotation untouched.
  993. ////////////////////////////////////////////////////////////////////
  994. void NodePath::
  995. set_shear(const LVecBase3f &shear) {
  996. nassertv_always(!is_empty());
  997. CPT(TransformState) transform = get_transform();
  998. set_transform(transform->set_shear(shear));
  999. }
  1000. void NodePath::
  1001. set_shxy(float shxy) {
  1002. nassertv_always(!is_empty());
  1003. CPT(TransformState) transform = get_transform();
  1004. LVecBase3f shear = transform->get_shear();
  1005. shear[0] = shxy;
  1006. set_transform(transform->set_shear(shear));
  1007. }
  1008. void NodePath::
  1009. set_shxz(float shxz) {
  1010. nassertv_always(!is_empty());
  1011. CPT(TransformState) transform = get_transform();
  1012. LVecBase3f shear = transform->get_shear();
  1013. shear[1] = shxz;
  1014. set_transform(transform->set_shear(shear));
  1015. }
  1016. void NodePath::
  1017. set_shyz(float shyz) {
  1018. nassertv_always(!is_empty());
  1019. CPT(TransformState) transform = get_transform();
  1020. LVecBase3f shear = transform->get_shear();
  1021. shear[2] = shyz;
  1022. set_transform(transform->set_shear(shear));
  1023. }
  1024. ////////////////////////////////////////////////////////////////////
  1025. // Function: NodePath::get_shear
  1026. // Access: Published
  1027. // Description: Retrieves the shear component of the transform.
  1028. ////////////////////////////////////////////////////////////////////
  1029. LVecBase3f NodePath::
  1030. get_shear() const {
  1031. nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
  1032. CPT(TransformState) transform = get_transform();
  1033. return transform->get_shear();
  1034. }
  1035. ////////////////////////////////////////////////////////////////////
  1036. // Function: NodePath::set_pos_hpr
  1037. // Access: Published
  1038. // Description: Sets the translation and rotation component of the
  1039. // transform, leaving scale untouched.
  1040. ////////////////////////////////////////////////////////////////////
  1041. void NodePath::
  1042. set_pos_hpr(const LVecBase3f &pos, const LVecBase3f &hpr) {
  1043. nassertv_always(!is_empty());
  1044. CPT(TransformState) transform = get_transform();
  1045. transform = TransformState::make_pos_hpr_scale_shear
  1046. (pos, hpr, transform->get_scale(), transform->get_shear());
  1047. set_transform(transform);
  1048. node()->reset_prev_transform();
  1049. }
  1050. ////////////////////////////////////////////////////////////////////
  1051. // Function: NodePath::set_pos_quat
  1052. // Access: Published
  1053. // Description: Sets the translation and rotation component of the
  1054. // transform, leaving scale untouched.
  1055. ////////////////////////////////////////////////////////////////////
  1056. void NodePath::
  1057. set_pos_quat(const LVecBase3f &pos, const LQuaternionf &quat) {
  1058. nassertv_always(!is_empty());
  1059. CPT(TransformState) transform = get_transform();
  1060. transform = TransformState::make_pos_quat_scale_shear
  1061. (pos, quat, transform->get_scale(), transform->get_shear());
  1062. set_transform(transform);
  1063. node()->reset_prev_transform();
  1064. }
  1065. ////////////////////////////////////////////////////////////////////
  1066. // Function: NodePath::set_hpr_scale
  1067. // Access: Published
  1068. // Description: Sets the rotation and scale components of the
  1069. // transform, leaving translation untouched.
  1070. ////////////////////////////////////////////////////////////////////
  1071. void NodePath::
  1072. set_hpr_scale(const LVecBase3f &hpr, const LVecBase3f &scale) {
  1073. nassertv_always(!is_empty());
  1074. CPT(TransformState) transform = get_transform();
  1075. transform = TransformState::make_pos_hpr_scale_shear
  1076. (transform->get_pos(), hpr, scale, transform->get_shear());
  1077. set_transform(transform);
  1078. }
  1079. ////////////////////////////////////////////////////////////////////
  1080. // Function: NodePath::set_quat_scale
  1081. // Access: Published
  1082. // Description: Sets the rotation and scale components of the
  1083. // transform, leaving translation untouched.
  1084. ////////////////////////////////////////////////////////////////////
  1085. void NodePath::
  1086. set_quat_scale(const LQuaternionf &quat, const LVecBase3f &scale) {
  1087. nassertv_always(!is_empty());
  1088. CPT(TransformState) transform = get_transform();
  1089. transform = TransformState::make_pos_quat_scale_shear
  1090. (transform->get_pos(), quat, scale, transform->get_shear());
  1091. set_transform(transform);
  1092. }
  1093. ////////////////////////////////////////////////////////////////////
  1094. // Function: NodePath::set_pos_hpr_scale
  1095. // Access: Published
  1096. // Description: Replaces the translation, rotation, and scale
  1097. // components, implicitly setting shear to 0.
  1098. ////////////////////////////////////////////////////////////////////
  1099. void NodePath::
  1100. set_pos_hpr_scale(const LVecBase3f &pos, const LVecBase3f &hpr,
  1101. const LVecBase3f &scale) {
  1102. nassertv_always(!is_empty());
  1103. set_transform(TransformState::make_pos_hpr_scale
  1104. (pos, hpr, scale));
  1105. node()->reset_prev_transform();
  1106. }
  1107. ////////////////////////////////////////////////////////////////////
  1108. // Function: NodePath::set_pos_quat_scale
  1109. // Access: Published
  1110. // Description: Replaces the translation, rotation, and scale
  1111. // components, implicitly setting shear to 0.
  1112. ////////////////////////////////////////////////////////////////////
  1113. void NodePath::
  1114. set_pos_quat_scale(const LVecBase3f &pos, const LQuaternionf &quat,
  1115. const LVecBase3f &scale) {
  1116. nassertv_always(!is_empty());
  1117. set_transform(TransformState::make_pos_quat_scale
  1118. (pos, quat, scale));
  1119. node()->reset_prev_transform();
  1120. }
  1121. ////////////////////////////////////////////////////////////////////
  1122. // Function: NodePath::set_pos_hpr_scale_shear
  1123. // Access: Published
  1124. // Description: Completely replaces the transform with new
  1125. // translation, rotation, scale, and shear components.
  1126. ////////////////////////////////////////////////////////////////////
  1127. void NodePath::
  1128. set_pos_hpr_scale_shear(const LVecBase3f &pos, const LVecBase3f &hpr,
  1129. const LVecBase3f &scale, const LVecBase3f &shear) {
  1130. nassertv_always(!is_empty());
  1131. set_transform(TransformState::make_pos_hpr_scale_shear
  1132. (pos, hpr, scale, shear));
  1133. node()->reset_prev_transform();
  1134. }
  1135. ////////////////////////////////////////////////////////////////////
  1136. // Function: NodePath::set_pos_quat_scale_shear
  1137. // Access: Published
  1138. // Description: Completely replaces the transform with new
  1139. // translation, rotation, scale, and shear components.
  1140. ////////////////////////////////////////////////////////////////////
  1141. void NodePath::
  1142. set_pos_quat_scale_shear(const LVecBase3f &pos, const LQuaternionf &quat,
  1143. const LVecBase3f &scale, const LVecBase3f &shear) {
  1144. nassertv_always(!is_empty());
  1145. set_transform(TransformState::make_pos_quat_scale_shear
  1146. (pos, quat, scale, shear));
  1147. node()->reset_prev_transform();
  1148. }
  1149. ////////////////////////////////////////////////////////////////////
  1150. // Function: NodePath::set_mat
  1151. // Access: Published
  1152. // Description: Directly sets an arbitrary 4x4 transform matrix.
  1153. ////////////////////////////////////////////////////////////////////
  1154. void NodePath::
  1155. set_mat(const LMatrix4f &mat) {
  1156. nassertv_always(!is_empty());
  1157. set_transform(TransformState::make_mat(mat));
  1158. node()->reset_prev_transform();
  1159. }
  1160. ////////////////////////////////////////////////////////////////////
  1161. // Function: NodePath::look_at
  1162. // Access: Published
  1163. // Description: Sets the hpr on this NodePath so that it
  1164. // rotates to face the indicated point in space.
  1165. ////////////////////////////////////////////////////////////////////
  1166. void NodePath::
  1167. look_at(const LPoint3f &point, const LVector3f &up) {
  1168. nassertv_always(!is_empty());
  1169. LPoint3f pos = get_pos();
  1170. LQuaternionf quat;
  1171. ::look_at(quat, point - pos, up);
  1172. set_quat(quat);
  1173. }
  1174. ////////////////////////////////////////////////////////////////////
  1175. // Function: NodePath::heads_up
  1176. // Access: Published
  1177. // Description: Behaves like look_at(), but with a strong preference
  1178. // to keeping the up vector oriented in the indicated
  1179. // "up" direction.
  1180. ////////////////////////////////////////////////////////////////////
  1181. void NodePath::
  1182. heads_up(const LPoint3f &point, const LVector3f &up) {
  1183. nassertv_always(!is_empty());
  1184. LPoint3f pos = get_pos();
  1185. LQuaternionf quat;
  1186. ::heads_up(quat, point - pos, up);
  1187. set_quat(quat);
  1188. }
  1189. ////////////////////////////////////////////////////////////////////
  1190. // Function: NodePath::set_pos
  1191. // Access: Published
  1192. // Description: Sets the translation component of the transform,
  1193. // relative to the other node.
  1194. ////////////////////////////////////////////////////////////////////
  1195. void NodePath::
  1196. set_pos(const NodePath &other, const LVecBase3f &pos) {
  1197. nassertv_always(!is_empty());
  1198. CPT(TransformState) rel_transform = get_transform(other);
  1199. CPT(TransformState) orig_transform = get_transform();
  1200. if (orig_transform->has_components()) {
  1201. // If we had a componentwise transform before we started, we
  1202. // should be careful to preserve the other three components. We
  1203. // wouldn't need to do this, except for the possibility of
  1204. // numerical error or decompose ambiguity.
  1205. const LVecBase3f &orig_hpr = orig_transform->get_hpr();
  1206. const LVecBase3f &orig_scale = orig_transform->get_scale();
  1207. const LVecBase3f &orig_shear = orig_transform->get_shear();
  1208. set_transform(other, rel_transform->set_pos(pos));
  1209. set_pos_hpr_scale_shear(get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear);
  1210. } else {
  1211. // If we didn't have a componentwise transform already, never
  1212. // mind.
  1213. set_transform(other, rel_transform->set_pos(pos));
  1214. }
  1215. node()->reset_prev_transform();
  1216. }
  1217. void NodePath::
  1218. set_x(const NodePath &other, float x) {
  1219. nassertv_always(!is_empty());
  1220. LPoint3f pos = get_pos(other);
  1221. pos[0] = x;
  1222. set_pos(other, pos);
  1223. }
  1224. void NodePath::
  1225. set_y(const NodePath &other, float y) {
  1226. nassertv_always(!is_empty());
  1227. LPoint3f pos = get_pos(other);
  1228. pos[1] = y;
  1229. set_pos(other, pos);
  1230. }
  1231. void NodePath::
  1232. set_z(const NodePath &other, float z) {
  1233. nassertv_always(!is_empty());
  1234. LPoint3f pos = get_pos(other);
  1235. pos[2] = z;
  1236. set_pos(other, pos);
  1237. }
  1238. ////////////////////////////////////////////////////////////////////
  1239. // Function: NodePath::set_fluid_pos
  1240. // Access: Published
  1241. // Description: Sets the translation component of the transform,
  1242. // relative to the other node.
  1243. ////////////////////////////////////////////////////////////////////
  1244. void NodePath::
  1245. set_fluid_pos(const NodePath &other, const LVecBase3f &pos) {
  1246. nassertv_always(!is_empty());
  1247. CPT(TransformState) rel_transform = get_transform(other);
  1248. CPT(TransformState) orig_transform = get_transform();
  1249. if (orig_transform->has_components()) {
  1250. // If we had a componentwise transform before we started, we
  1251. // should be careful to preserve the other three components. We
  1252. // wouldn't need to do this, except for the possibility of
  1253. // numerical error or decompose ambiguity.
  1254. const LVecBase3f &orig_hpr = orig_transform->get_hpr();
  1255. const LVecBase3f &orig_scale = orig_transform->get_scale();
  1256. const LVecBase3f &orig_shear = orig_transform->get_shear();
  1257. // Use the relative set_transform() to compute the relative pos, and
  1258. // then reset all of the other components back to the way they were.
  1259. set_transform(other, rel_transform->set_pos(pos));
  1260. set_transform(TransformState::make_pos_hpr_scale_shear
  1261. (get_transform()->get_pos(), orig_hpr, orig_scale, orig_shear));
  1262. } else {
  1263. // If we didn't have a componentwise transform already, never
  1264. // mind.
  1265. set_transform(other, rel_transform->set_pos(pos));
  1266. }
  1267. }
  1268. void NodePath::
  1269. set_fluid_x(const NodePath &other, float x) {
  1270. nassertv_always(!is_empty());
  1271. LPoint3f pos = get_pos(other);
  1272. pos[0] = x;
  1273. set_fluid_pos(other, pos);
  1274. }
  1275. void NodePath::
  1276. set_fluid_y(const NodePath &other, float y) {
  1277. nassertv_always(!is_empty());
  1278. LPoint3f pos = get_pos(other);
  1279. pos[1] = y;
  1280. set_fluid_pos(other, pos);
  1281. }
  1282. void NodePath::
  1283. set_fluid_z(const NodePath &other, float z) {
  1284. nassertv_always(!is_empty());
  1285. LPoint3f pos = get_pos(other);
  1286. pos[2] = z;
  1287. set_fluid_pos(other, pos);
  1288. }
  1289. ////////////////////////////////////////////////////////////////////
  1290. // Function: NodePath::get_pos
  1291. // Access: Published
  1292. // Description: Returns the relative position of the referenced node
  1293. // as seen from the other node.
  1294. ////////////////////////////////////////////////////////////////////
  1295. LPoint3f NodePath::
  1296. get_pos(const NodePath &other) const {
  1297. nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
  1298. return get_transform(other)->get_pos();
  1299. }
  1300. ////////////////////////////////////////////////////////////////////
  1301. // Function: NodePath::get_pos_delta
  1302. // Access: Published
  1303. // Description: Returns the delta vector from this node's position in
  1304. // the previous frame (according to
  1305. // set_prev_transform(), typically set via the use of
  1306. // set_fluid_pos()) and its position in the current
  1307. // frame, as seen in the indicated node's coordinate
  1308. // space. This is the vector used to determine
  1309. // collisions. Generally, if the node was last
  1310. // repositioned via set_pos(), the delta will be zero;
  1311. // if it was adjusted via set_fluid_pos(), the delta
  1312. // will represent the change from the previous frame's
  1313. // position.
  1314. ////////////////////////////////////////////////////////////////////
  1315. LVector3f NodePath::
  1316. get_pos_delta(const NodePath &other) const {
  1317. nassertr_always(!is_empty(), LPoint3f(0.0f, 0.0f, 0.0f));
  1318. return get_transform(other)->get_pos() - get_prev_transform(other)->get_pos();
  1319. }
  1320. ////////////////////////////////////////////////////////////////////
  1321. // Function: NodePath::set_hpr
  1322. // Access: Published
  1323. // Description: Sets the rotation component of the transform,
  1324. // relative to the other node.
  1325. ////////////////////////////////////////////////////////////////////
  1326. void NodePath::
  1327. set_hpr(const NodePath &other, const LVecBase3f &hpr) {
  1328. nassertv_always(!is_empty());
  1329. CPT(TransformState) rel_transform = get_transform(other);
  1330. nassertv(rel_transform->has_hpr());
  1331. CPT(TransformState) orig_transform = get_transform();
  1332. if (orig_transform->has_components()) {
  1333. // If we had a componentwise transform before we started, we
  1334. // should be careful to preserve the other three components. We
  1335. // wouldn't need to do this, except for the possibility of
  1336. // numerical error or decompose ambiguity.
  1337. const LVecBase3f &orig_pos = orig_transform->get_pos();
  1338. const LVecBase3f &orig_scale = orig_transform->get_scale();
  1339. const LVecBase3f &orig_shear = orig_transform->get_shear();
  1340. set_transform(other, rel_transform->set_hpr(hpr));
  1341. const TransformState *new_transform = get_transform();
  1342. if (new_transform->has_components()) {
  1343. set_transform(TransformState::make_pos_hpr_scale_shear
  1344. (orig_pos, new_transform->get_hpr(), orig_scale, orig_shear));
  1345. }
  1346. } else {
  1347. // If we didn't have a componentwise transform already, never
  1348. // mind.
  1349. set_transform(other, rel_transform->set_hpr(hpr));
  1350. }
  1351. }
  1352. void NodePath::
  1353. set_h(const NodePath &other, float h) {
  1354. nassertv_always(!is_empty());
  1355. LVecBase3f hpr = get_hpr(other);
  1356. hpr[0] = h;
  1357. set_hpr(other, hpr);
  1358. }
  1359. void NodePath::
  1360. set_p(const NodePath &other, float p) {
  1361. nassertv_always(!is_empty());
  1362. LVecBase3f hpr = get_hpr(other);
  1363. hpr[1] = p;
  1364. set_hpr(other, hpr);
  1365. }
  1366. void NodePath::
  1367. set_r(const NodePath &other, float r) {
  1368. nassertv_always(!is_empty());
  1369. LVecBase3f hpr = get_hpr(other);
  1370. hpr[2] = r;
  1371. set_hpr(other, hpr);
  1372. }
  1373. ////////////////////////////////////////////////////////////////////
  1374. // Function: NodePath::get_hpr
  1375. // Access: Published
  1376. // Description: Returns the relative orientation of the bottom node
  1377. // as seen from the other node.
  1378. ////////////////////////////////////////////////////////////////////
  1379. LVecBase3f NodePath::
  1380. get_hpr(const NodePath &other) const {
  1381. nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
  1382. CPT(TransformState) transform = get_transform(other);
  1383. nassertr(transform->has_hpr(), LVecBase3f(0.0f, 0.0f, 0.0f));
  1384. return transform->get_hpr();
  1385. }
  1386. ////////////////////////////////////////////////////////////////////
  1387. // Function: NodePath::set_quat
  1388. // Access: Published
  1389. // Description: Sets the rotation component of the transform,
  1390. // relative to the other node.
  1391. ////////////////////////////////////////////////////////////////////
  1392. void NodePath::
  1393. set_quat(const NodePath &other, const LQuaternionf &quat) {
  1394. nassertv_always(!is_empty());
  1395. CPT(TransformState) rel_transform = get_transform(other);
  1396. CPT(TransformState) orig_transform = get_transform();
  1397. if (orig_transform->has_components()) {
  1398. // If we had a componentwise transform before we started, we
  1399. // should be careful to preserve the other three components. We
  1400. // wouldn't need to do this, except for the possibility of
  1401. // numerical error or decompose ambiguity.
  1402. const LVecBase3f &orig_pos = orig_transform->get_pos();
  1403. const LVecBase3f &orig_scale = orig_transform->get_scale();
  1404. const LVecBase3f &orig_shear = orig_transform->get_shear();
  1405. set_transform(other, rel_transform->set_quat(quat));
  1406. const TransformState *new_transform = get_transform();
  1407. if (new_transform->has_components()) {
  1408. set_transform(TransformState::make_pos_quat_scale_shear
  1409. (orig_pos, new_transform->get_quat(), orig_scale, orig_shear));
  1410. }
  1411. } else {
  1412. // If we didn't have a componentwise transform already, never
  1413. // mind.
  1414. set_transform(other, rel_transform->set_quat(quat));
  1415. }
  1416. }
  1417. ////////////////////////////////////////////////////////////////////
  1418. // Function: NodePath::get_quat
  1419. // Access: Published
  1420. // Description: Returns the relative orientation of the bottom node
  1421. // as seen from the other node.
  1422. ////////////////////////////////////////////////////////////////////
  1423. LQuaternionf NodePath::
  1424. get_quat(const NodePath &other) const {
  1425. nassertr_always(!is_empty(), LQuaternionf::ident_quat());
  1426. CPT(TransformState) transform = get_transform(other);
  1427. return transform->get_quat();
  1428. }
  1429. ////////////////////////////////////////////////////////////////////
  1430. // Function: NodePath::set_scale
  1431. // Access: Published
  1432. // Description: Sets the scale component of the transform,
  1433. // relative to the other node.
  1434. ////////////////////////////////////////////////////////////////////
  1435. void NodePath::
  1436. set_scale(const NodePath &other, const LVecBase3f &scale) {
  1437. nassertv_always(!is_empty());
  1438. CPT(TransformState) rel_transform = get_transform(other);
  1439. CPT(TransformState) orig_transform = get_transform();
  1440. if (orig_transform->has_components()) {
  1441. // If we had a componentwise transform before we started, we
  1442. // should be careful to preserve the other three components. We
  1443. // wouldn't need to do this, except for the possibility of
  1444. // numerical error or decompose ambiguity.
  1445. const LVecBase3f &orig_pos = orig_transform->get_pos();
  1446. const LVecBase3f &orig_hpr = orig_transform->get_hpr();
  1447. const LVecBase3f &orig_shear = orig_transform->get_shear();
  1448. set_transform(other, rel_transform->set_scale(scale));
  1449. const TransformState *new_transform = get_transform();
  1450. if (new_transform->has_components()) {
  1451. set_transform(TransformState::make_pos_hpr_scale_shear
  1452. (orig_pos, orig_hpr, new_transform->get_scale(), orig_shear));
  1453. }
  1454. } else {
  1455. // If we didn't have a componentwise transform already, never
  1456. // mind.
  1457. set_transform(other, rel_transform->set_scale(scale));
  1458. }
  1459. }
  1460. void NodePath::
  1461. set_sx(const NodePath &other, float sx) {
  1462. nassertv_always(!is_empty());
  1463. LVecBase3f scale = get_scale(other);
  1464. scale[0] = sx;
  1465. set_scale(other, scale);
  1466. }
  1467. void NodePath::
  1468. set_sy(const NodePath &other, float sy) {
  1469. nassertv_always(!is_empty());
  1470. LVecBase3f scale = get_scale(other);
  1471. scale[1] = sy;
  1472. set_scale(other, scale);
  1473. }
  1474. void NodePath::
  1475. set_sz(const NodePath &other, float sz) {
  1476. nassertv_always(!is_empty());
  1477. LVecBase3f scale = get_scale(other);
  1478. scale[2] = sz;
  1479. set_scale(other, scale);
  1480. }
  1481. ////////////////////////////////////////////////////////////////////
  1482. // Function: NodePath::get_scale
  1483. // Access: Published
  1484. // Description: Returns the relative scale of the bottom node
  1485. // as seen from the other node.
  1486. ////////////////////////////////////////////////////////////////////
  1487. LVecBase3f NodePath::
  1488. get_scale(const NodePath &other) const {
  1489. nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
  1490. CPT(TransformState) transform = get_transform(other);
  1491. return transform->get_scale();
  1492. }
  1493. ////////////////////////////////////////////////////////////////////
  1494. // Function: NodePath::set_shear
  1495. // Access: Published
  1496. // Description: Sets the shear component of the transform,
  1497. // relative to the other node.
  1498. ////////////////////////////////////////////////////////////////////
  1499. void NodePath::
  1500. set_shear(const NodePath &other, const LVecBase3f &shear) {
  1501. nassertv_always(!is_empty());
  1502. CPT(TransformState) rel_transform = get_transform(other);
  1503. CPT(TransformState) orig_transform = get_transform();
  1504. if (orig_transform->has_components()) {
  1505. // If we had a componentwise transform before we started, we
  1506. // should be careful to preserve the other three components. We
  1507. // wouldn't need to do this, except for the possibility of
  1508. // numerical error or decompose ambiguity.
  1509. const LVecBase3f &orig_pos = orig_transform->get_pos();
  1510. const LVecBase3f &orig_hpr = orig_transform->get_hpr();
  1511. const LVecBase3f &orig_scale = orig_transform->get_scale();
  1512. set_transform(other, rel_transform->set_shear(shear));
  1513. const TransformState *new_transform = get_transform();
  1514. if (new_transform->has_components()) {
  1515. set_transform(TransformState::make_pos_hpr_scale_shear
  1516. (orig_pos, orig_hpr, orig_scale, new_transform->get_shear()));
  1517. }
  1518. } else {
  1519. // If we didn't have a componentwise transform already, never
  1520. // mind.
  1521. set_transform(other, rel_transform->set_shear(shear));
  1522. }
  1523. }
  1524. void NodePath::
  1525. set_shxy(const NodePath &other, float shxy) {
  1526. nassertv_always(!is_empty());
  1527. LVecBase3f shear = get_shear(other);
  1528. shear[0] = shxy;
  1529. set_shear(other, shear);
  1530. }
  1531. void NodePath::
  1532. set_shxz(const NodePath &other, float shxz) {
  1533. nassertv_always(!is_empty());
  1534. LVecBase3f shear = get_shear(other);
  1535. shear[1] = shxz;
  1536. set_shear(other, shear);
  1537. }
  1538. void NodePath::
  1539. set_shyz(const NodePath &other, float shyz) {
  1540. nassertv_always(!is_empty());
  1541. LVecBase3f shear = get_shear(other);
  1542. shear[2] = shyz;
  1543. set_shear(other, shear);
  1544. }
  1545. ////////////////////////////////////////////////////////////////////
  1546. // Function: NodePath::get_shear
  1547. // Access: Published
  1548. // Description: Returns the relative shear of the bottom node
  1549. // as seen from the other node.
  1550. ////////////////////////////////////////////////////////////////////
  1551. LVecBase3f NodePath::
  1552. get_shear(const NodePath &other) const {
  1553. nassertr_always(!is_empty(), LVecBase3f(0.0f, 0.0f, 0.0f));
  1554. CPT(TransformState) transform = get_transform(other);
  1555. return transform->get_shear();
  1556. }
  1557. ////////////////////////////////////////////////////////////////////
  1558. // Function: NodePath::set_pos_hpr
  1559. // Access: Published
  1560. // Description: Sets the translation and rotation component of the
  1561. // transform, relative to the other node.
  1562. ////////////////////////////////////////////////////////////////////
  1563. void NodePath::
  1564. set_pos_hpr(const NodePath &other, const LVecBase3f &pos,
  1565. const LVecBase3f &hpr) {
  1566. nassertv_always(!is_empty());
  1567. CPT(TransformState) rel_transform = get_transform(other);
  1568. CPT(TransformState) orig_transform = get_transform();
  1569. if (orig_transform->has_components()) {
  1570. // If we had a componentwise transform before we started, we
  1571. // should be careful to preserve the other two components. We
  1572. // wouldn't need to do this, except for the possibility of
  1573. // numerical error or decompose ambiguity.
  1574. const LVecBase3f &orig_scale = orig_transform->get_scale();
  1575. const LVecBase3f &orig_shear = orig_transform->get_shear();
  1576. set_transform(other, TransformState::make_pos_hpr_scale_shear
  1577. (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
  1578. const TransformState *new_transform = get_transform();
  1579. if (new_transform->has_components()) {
  1580. set_pos_hpr_scale_shear(new_transform->get_pos(), new_transform->get_hpr(),
  1581. orig_scale, orig_shear);
  1582. }
  1583. } else {
  1584. // If we didn't have a componentwise transform already, never
  1585. // mind.
  1586. set_transform(other, TransformState::make_pos_hpr_scale_shear
  1587. (pos, hpr, rel_transform->get_scale(), rel_transform->get_shear()));
  1588. node()->reset_prev_transform();
  1589. }
  1590. }
  1591. ////////////////////////////////////////////////////////////////////
  1592. // Function: NodePath::set_pos_quat
  1593. // Access: Published
  1594. // Description: Sets the translation and rotation component of the
  1595. // transform, relative to the other node.
  1596. ////////////////////////////////////////////////////////////////////
  1597. void NodePath::
  1598. set_pos_quat(const NodePath &other, const LVecBase3f &pos,
  1599. const LQuaternionf &quat) {
  1600. nassertv_always(!is_empty());
  1601. CPT(TransformState) rel_transform = get_transform(other);
  1602. CPT(TransformState) orig_transform = get_transform();
  1603. if (orig_transform->has_components()) {
  1604. // If we had a componentwise transform before we started, we
  1605. // should be careful to preserve the other two components. We
  1606. // wouldn't need to do this, except for the possibility of
  1607. // numerical error or decompose ambiguity.
  1608. const LVecBase3f &orig_scale = orig_transform->get_scale();
  1609. const LVecBase3f &orig_shear = orig_transform->get_shear();
  1610. set_transform(other, TransformState::make_pos_quat_scale_shear
  1611. (pos, quat, rel_transform->get_scale(), rel_transform->get_shear()));
  1612. const TransformState *new_transform = get_transform();
  1613. if (new_transform->has_components()) {
  1614. set_pos_quat_scale_shear(new_transform->get_pos(), new_transform->get_quat(),
  1615. orig_scale, orig_shear);
  1616. }
  1617. } else {
  1618. // If we didn't have a componentwise transform already, never
  1619. // mind.
  1620. set_transform(other, TransformState::make_pos_quat_scale_shear
  1621. (pos, quat, rel_transform->get_scale(), rel_transform->get_shear()));
  1622. node()->reset_prev_transform();
  1623. }
  1624. }
  1625. ////////////////////////////////////////////////////////////////////
  1626. // Function: NodePath::set_hpr_scale
  1627. // Access: Published
  1628. // Description: Sets the rotation and scale components of the
  1629. // transform, leaving translation untouched. This, or
  1630. // set_pos_hpr_scale, is the preferred way to update a
  1631. // transform when both hpr and scale are to be changed.
  1632. ////////////////////////////////////////////////////////////////////
  1633. void NodePath::
  1634. set_hpr_scale(const NodePath &other, const LVecBase3f &hpr, const LVecBase3f &scale) {
  1635. // We don't bother trying very hard to preserve pos across this
  1636. // operation, unlike the work we do above to preserve hpr or scale,
  1637. // since it generally doesn't matter that much if pos is off by a
  1638. // few thousandths.
  1639. nassertv_always(!is_empty());
  1640. CPT(TransformState) transform = get_transform(other);
  1641. transform = TransformState::make_pos_hpr_scale_shear
  1642. (transform->get_pos(), hpr, scale, transform->get_shear());
  1643. set_transform(other, transform);
  1644. }
  1645. ////////////////////////////////////////////////////////////////////
  1646. // Function: NodePath::set_quat_scale
  1647. // Access: Published
  1648. // Description: Sets the rotation and scale components of the
  1649. // transform, leaving translation untouched. This, or
  1650. // set_pos_quat_scale, is the preferred way to update a
  1651. // transform when both quat and scale are to be changed.
  1652. ////////////////////////////////////////////////////////////////////
  1653. void NodePath::
  1654. set_quat_scale(const NodePath &other, const LQuaternionf &quat,
  1655. const LVecBase3f &scale) {
  1656. // We don't bother trying very hard to preserve pos across this
  1657. // operation, unlike the work we do above to preserve quat or scale,
  1658. // since it generally doesn't matter that much if pos is off by a
  1659. // few thousandths.
  1660. nassertv_always(!is_empty());
  1661. CPT(TransformState) transform = get_transform(other);
  1662. transform = TransformState::make_pos_quat_scale_shear
  1663. (transform->get_pos(), quat, scale, transform->get_shear());
  1664. set_transform(other, transform);
  1665. }
  1666. ////////////////////////////////////////////////////////////////////
  1667. // Function: NodePath::set_pos_hpr_scale
  1668. // Access: Published
  1669. // Description: Completely replaces the transform with new
  1670. // translation, rotation, and scale components, relative
  1671. // to the other node, implicitly setting shear to 0.
  1672. ////////////////////////////////////////////////////////////////////
  1673. void NodePath::
  1674. set_pos_hpr_scale(const NodePath &other,
  1675. const LVecBase3f &pos, const LVecBase3f &hpr,
  1676. const LVecBase3f &scale) {
  1677. nassertv_always(!is_empty());
  1678. set_transform(other, TransformState::make_pos_hpr_scale
  1679. (pos, hpr, scale));
  1680. node()->reset_prev_transform();
  1681. }
  1682. ////////////////////////////////////////////////////////////////////
  1683. // Function: NodePath::set_pos_quat_scale
  1684. // Access: Published
  1685. // Description: Completely replaces the transform with new
  1686. // translation, rotation, and scale components, relative
  1687. // to the other node, implicitly setting shear to 0.
  1688. ////////////////////////////////////////////////////////////////////
  1689. void NodePath::
  1690. set_pos_quat_scale(const NodePath &other,
  1691. const LVecBase3f &pos, const LQuaternionf &quat,
  1692. const LVecBase3f &scale) {
  1693. nassertv_always(!is_empty());
  1694. set_transform(other, TransformState::make_pos_quat_scale
  1695. (pos, quat, scale));
  1696. node()->reset_prev_transform();
  1697. }
  1698. ////////////////////////////////////////////////////////////////////
  1699. // Function: NodePath::set_pos_hpr_scale_shear
  1700. // Access: Published
  1701. // Description: Completely replaces the transform with new
  1702. // translation, rotation, scale, and shear components,
  1703. // relative to the other node.
  1704. ////////////////////////////////////////////////////////////////////
  1705. void NodePath::
  1706. set_pos_hpr_scale_shear(const NodePath &other,
  1707. const LVecBase3f &pos, const LVecBase3f &hpr,
  1708. const LVecBase3f &scale, const LVecBase3f &shear) {
  1709. nassertv_always(!is_empty());
  1710. set_transform(other, TransformState::make_pos_hpr_scale_shear
  1711. (pos, hpr, scale, shear));
  1712. node()->reset_prev_transform();
  1713. }
  1714. ////////////////////////////////////////////////////////////////////
  1715. // Function: NodePath::set_pos_quat_scale_shear
  1716. // Access: Published
  1717. // Description: Completely replaces the transform with new
  1718. // translation, rotation, scale, and shear components,
  1719. // relative to the other node.
  1720. ////////////////////////////////////////////////////////////////////
  1721. void NodePath::
  1722. set_pos_quat_scale_shear(const NodePath &other,
  1723. const LVecBase3f &pos, const LQuaternionf &quat,
  1724. const LVecBase3f &scale, const LVecBase3f &shear) {
  1725. nassertv_always(!is_empty());
  1726. set_transform(other, TransformState::make_pos_quat_scale_shear
  1727. (pos, quat, scale, shear));
  1728. node()->reset_prev_transform();
  1729. }
  1730. ////////////////////////////////////////////////////////////////////
  1731. // Function: NodePath::get_mat
  1732. // Access: Published
  1733. // Description: Returns the matrix that describes the coordinate
  1734. // space of the bottom node, relative to the other
  1735. // path's bottom node's coordinate space.
  1736. ////////////////////////////////////////////////////////////////////
  1737. LMatrix4f NodePath::
  1738. get_mat(const NodePath &other) const {
  1739. CPT(TransformState) transform = get_transform(other);
  1740. // We can't safely return a reference to the matrix, because we
  1741. // can't assume the transform won't go away when the function
  1742. // returns. If the transform was partially modified by, say, a
  1743. // CompassEffect, it won't be stored in the cache, and thus we might
  1744. // have the only reference to it.
  1745. return transform->get_mat();
  1746. }
  1747. ////////////////////////////////////////////////////////////////////
  1748. // Function: NodePath::set_mat
  1749. // Access: Published
  1750. // Description: Converts the indicated matrix from the other's
  1751. // coordinate space to the local coordinate space, and
  1752. // applies it to the node.
  1753. ////////////////////////////////////////////////////////////////////
  1754. void NodePath::
  1755. set_mat(const NodePath &other, const LMatrix4f &mat) {
  1756. nassertv_always(!is_empty());
  1757. set_transform(other, TransformState::make_mat(mat));
  1758. node()->reset_prev_transform();
  1759. }
  1760. ////////////////////////////////////////////////////////////////////
  1761. // Function: NodePath::get_relative_point
  1762. // Access: Published
  1763. // Description: Given that the indicated point is in the coordinate
  1764. // system of the other node, returns the same point in
  1765. // this node's coordinate system.
  1766. ////////////////////////////////////////////////////////////////////
  1767. LPoint3f NodePath::
  1768. get_relative_point(const NodePath &other, const LVecBase3f &point) const {
  1769. CPT(TransformState) transform = other.get_transform(*this);
  1770. LPoint3f rel_point = LPoint3f(point) * transform->get_mat();
  1771. return rel_point;
  1772. }
  1773. ////////////////////////////////////////////////////////////////////
  1774. // Function: NodePath::get_relative_vector
  1775. // Access: Published
  1776. // Description: Given that the indicated vector is in the coordinate
  1777. // system of the other node, returns the same vector in
  1778. // this node's coordinate system.
  1779. ////////////////////////////////////////////////////////////////////
  1780. LVector3f NodePath::
  1781. get_relative_vector(const NodePath &other, const LVecBase3f &vec) const {
  1782. CPT(TransformState) transform = other.get_transform(*this);
  1783. LVector3f rel_vector = LVector3f(vec) * transform->get_mat();
  1784. return rel_vector;
  1785. }
  1786. ////////////////////////////////////////////////////////////////////
  1787. // Function: NodePath::look_at
  1788. // Access: Published
  1789. // Description: Sets the transform on this NodePath so that it
  1790. // rotates to face the indicated point in space, which
  1791. // is relative to the other NodePath.
  1792. ////////////////////////////////////////////////////////////////////
  1793. void NodePath::
  1794. look_at(const NodePath &other, const LPoint3f &point, const LVector3f &up) {
  1795. nassertv_always(!is_empty());
  1796. CPT(TransformState) transform = other.get_transform(get_parent());
  1797. LPoint3f rel_point = point * transform->get_mat();
  1798. LPoint3f pos = get_pos();
  1799. LQuaternionf quat;
  1800. ::look_at(quat, rel_point - pos, up);
  1801. set_quat(quat);
  1802. }
  1803. ////////////////////////////////////////////////////////////////////
  1804. // Function: NodePath::heads_up
  1805. // Access: Published
  1806. // Description: Behaves like look_at(), but with a strong preference
  1807. // to keeping the up vector oriented in the indicated
  1808. // "up" direction.
  1809. ////////////////////////////////////////////////////////////////////
  1810. void NodePath::
  1811. heads_up(const NodePath &other, const LPoint3f &point, const LVector3f &up) {
  1812. nassertv_always(!is_empty());
  1813. CPT(TransformState) transform = other.get_transform(get_parent());
  1814. LPoint3f rel_point = point * transform->get_mat();
  1815. LPoint3f pos = get_pos();
  1816. LQuaternionf quat;
  1817. ::heads_up(quat, rel_point - pos, up);
  1818. set_quat(quat);
  1819. }
  1820. ////////////////////////////////////////////////////////////////////
  1821. // Function: NodePath::set_color
  1822. // Access: Published
  1823. // Description: Applies a scene-graph color to the referenced node.
  1824. // This color will apply to all geometry at this level
  1825. // and below (that does not specify a new color or a
  1826. // set_color_off()).
  1827. ////////////////////////////////////////////////////////////////////
  1828. void NodePath::
  1829. set_color(float r, float g, float b, float a,
  1830. int priority) {
  1831. set_color(Colorf(r, g, b, a), priority);
  1832. }
  1833. ////////////////////////////////////////////////////////////////////
  1834. // Function: NodePath::set_color
  1835. // Access: Published
  1836. // Description: Applies a scene-graph color to the referenced node.
  1837. // This color will apply to all geometry at this level
  1838. // and below (that does not specify a new color or a
  1839. // set_color_off()).
  1840. ////////////////////////////////////////////////////////////////////
  1841. void NodePath::
  1842. set_color(const Colorf &color, int priority) {
  1843. nassertv_always(!is_empty());
  1844. node()->set_attrib(ColorAttrib::make_flat(color), priority);
  1845. }
  1846. ////////////////////////////////////////////////////////////////////
  1847. // Function: NodePath::set_color_off
  1848. // Access: Published
  1849. // Description: Sets the geometry at this level and below to render
  1850. // using the geometry color. This is normally the
  1851. // default, but it may be useful to use this to
  1852. // contradict set_color() at a higher node level (or,
  1853. // with a priority, to override a set_color() at a lower
  1854. // level).
  1855. ////////////////////////////////////////////////////////////////////
  1856. void NodePath::
  1857. set_color_off(int priority) {
  1858. nassertv_always(!is_empty());
  1859. node()->set_attrib(ColorAttrib::make_vertex(), priority);
  1860. }
  1861. ////////////////////////////////////////////////////////////////////
  1862. // Function: NodePath::clear_color
  1863. // Access: Published
  1864. // Description: Completely removes any color adjustment from the node.
  1865. // This allows the natural color of the geometry, or
  1866. // whatever color transitions might be otherwise
  1867. // affecting the geometry, to show instead.
  1868. ////////////////////////////////////////////////////////////////////
  1869. void NodePath::
  1870. clear_color() {
  1871. nassertv_always(!is_empty());
  1872. node()->clear_attrib(ColorAttrib::get_class_type());
  1873. }
  1874. ////////////////////////////////////////////////////////////////////
  1875. // Function: NodePath::has_color
  1876. // Access: Published
  1877. // Description: Returns true if a color has been applied to the given
  1878. // node, false otherwise.
  1879. ////////////////////////////////////////////////////////////////////
  1880. bool NodePath::
  1881. has_color() const {
  1882. nassertr_always(!is_empty(), false);
  1883. return node()->has_attrib(ColorAttrib::get_class_type());
  1884. }
  1885. ////////////////////////////////////////////////////////////////////
  1886. // Function: NodePath::get_color
  1887. // Access: Published
  1888. // Description: Returns the color that has been assigned to the node,
  1889. // or black if no color has been assigned.
  1890. ////////////////////////////////////////////////////////////////////
  1891. Colorf NodePath::
  1892. get_color() const {
  1893. nassertr_always(!is_empty(), false);
  1894. const RenderAttrib *attrib =
  1895. node()->get_attrib(ColorAttrib::get_class_type());
  1896. if (attrib != (const RenderAttrib *)NULL) {
  1897. const ColorAttrib *ca = DCAST(ColorAttrib, attrib);
  1898. if (ca->get_color_type() == ColorAttrib::T_flat) {
  1899. return ca->get_color();
  1900. }
  1901. }
  1902. pgraph_cat.warning()
  1903. << "get_color() called on " << *this << " which has no color set.\n";
  1904. return Colorf(1.0f, 1.0f, 1.0f, 1.0f);
  1905. }
  1906. ////////////////////////////////////////////////////////////////////
  1907. // Function: NodePath::has_color_scale
  1908. // Access: Published
  1909. // Description: Returns true if a color scale has been applied
  1910. // to the referenced node, false otherwise. It is still
  1911. // possible that color at this node might have been
  1912. // scaled by an ancestor node.
  1913. ////////////////////////////////////////////////////////////////////
  1914. bool NodePath::
  1915. has_color_scale() const {
  1916. nassertr_always(!is_empty(), false);
  1917. return node()->has_attrib(ColorScaleAttrib::get_class_type());
  1918. }
  1919. ////////////////////////////////////////////////////////////////////
  1920. // Function: NodePath::clear_color_scale
  1921. // Access: Published
  1922. // Description: Completely removes any color scale from the
  1923. // referenced node. This is preferable to simply
  1924. // setting the color scale to identity, as it also
  1925. // removes the overhead associated with having a color
  1926. // scale at all.
  1927. ////////////////////////////////////////////////////////////////////
  1928. void NodePath::
  1929. clear_color_scale() {
  1930. nassertv_always(!is_empty());
  1931. node()->clear_attrib(ColorScaleAttrib::get_class_type());
  1932. }
  1933. ////////////////////////////////////////////////////////////////////
  1934. // Function: NodePath::set_color_scale
  1935. // Access: Published
  1936. // Description: Sets the color scale component of the transform,
  1937. // leaving translation and rotation untouched.
  1938. ////////////////////////////////////////////////////////////////////
  1939. void NodePath::
  1940. set_color_scale(const LVecBase4f &scale, int priority) {
  1941. nassertv_always(!is_empty());
  1942. const RenderAttrib *attrib =
  1943. node()->get_attrib(ColorScaleAttrib::get_class_type());
  1944. if (attrib != (const RenderAttrib *)NULL) {
  1945. priority = max(priority,
  1946. node()->get_state()->get_override(ColorScaleAttrib::get_class_type()));
  1947. const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
  1948. // Modify the existing ColorScaleAttrib to add the indicated
  1949. // colorScale.
  1950. node()->set_attrib(csa->set_scale(scale), priority);
  1951. } else {
  1952. // Create a new ColorScaleAttrib for this node.
  1953. node()->set_attrib(ColorScaleAttrib::make(scale), priority);
  1954. }
  1955. }
  1956. ////////////////////////////////////////////////////////////////////
  1957. // Function: NodePath::set_color_scale_off
  1958. // Access: Published
  1959. // Description: Disables any color scale attribute inherited from
  1960. // above. This is not the same thing as
  1961. // clear_color_scale(), which undoes any previous
  1962. // set_color_scale() operation on this node; rather,
  1963. // this actively disables any set_color_scale() that
  1964. // might be inherited from a parent node. This also
  1965. // disables set_alpha_scale() at the same time.
  1966. //
  1967. // It is legal to specify a new color scale on the same
  1968. // node with a subsequent call to set_color_scale() or
  1969. // set_alpha_scale(); this new scale will apply to lower
  1970. // geometry.
  1971. ////////////////////////////////////////////////////////////////////
  1972. void NodePath::
  1973. set_color_scale_off(int priority) {
  1974. nassertv_always(!is_empty());
  1975. node()->set_attrib(ColorScaleAttrib::make_off(), priority);
  1976. }
  1977. ////////////////////////////////////////////////////////////////////
  1978. // Function: NodePath::set_alpha_scale
  1979. // Access: Published
  1980. // Description: Sets the alpha scale component of the transform
  1981. // without (much) affecting the color scale. Note that
  1982. // any priority specified will also apply to the color
  1983. // scale.
  1984. ////////////////////////////////////////////////////////////////////
  1985. void NodePath::
  1986. set_alpha_scale(float scale, int priority) {
  1987. nassertv_always(!is_empty());
  1988. const RenderAttrib *attrib =
  1989. node()->get_attrib(ColorScaleAttrib::get_class_type());
  1990. if (attrib != (const RenderAttrib *)NULL) {
  1991. priority = max(priority,
  1992. node()->get_state()->get_override(ColorScaleAttrib::get_class_type()));
  1993. const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
  1994. // Modify the existing ColorScaleAttrib to add the indicated
  1995. // colorScale.
  1996. const LVecBase4f &sc = csa->get_scale();
  1997. node()->set_attrib(csa->set_scale(LVecBase4f(sc[0], sc[1], sc[2], scale)), priority);
  1998. } else {
  1999. // Create a new ColorScaleAttrib for this node.
  2000. node()->set_attrib(ColorScaleAttrib::make(LVecBase4f(1.0f, 1.0f, 1.0f, scale)), priority);
  2001. }
  2002. }
  2003. ////////////////////////////////////////////////////////////////////
  2004. // Function: NodePath::set_all_color_scale
  2005. // Access: Published
  2006. // Description: Scales all the color components of the object by the
  2007. // same amount, darkening the object, without (much)
  2008. // affecting alpha. Note that any priority specified
  2009. // will also apply to the alpha scale.
  2010. ////////////////////////////////////////////////////////////////////
  2011. void NodePath::
  2012. set_all_color_scale(float scale, int priority) {
  2013. nassertv_always(!is_empty());
  2014. const RenderAttrib *attrib =
  2015. node()->get_attrib(ColorScaleAttrib::get_class_type());
  2016. if (attrib != (const RenderAttrib *)NULL) {
  2017. priority = max(priority,
  2018. node()->get_state()->get_override(ColorScaleAttrib::get_class_type()));
  2019. const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
  2020. // Modify the existing ColorScaleAttrib to add the indicated
  2021. // colorScale.
  2022. const LVecBase4f &sc = csa->get_scale();
  2023. node()->set_attrib(csa->set_scale(LVecBase4f(scale, scale, scale, sc[3])), priority);
  2024. } else {
  2025. // Create a new ColorScaleAttrib for this node.
  2026. node()->set_attrib(ColorScaleAttrib::make(LVecBase4f(scale, scale, scale, 1.0f)), priority);
  2027. }
  2028. }
  2029. ////////////////////////////////////////////////////////////////////
  2030. // Function: NodePath::get_color_scale
  2031. // Access: Published
  2032. // Description: Returns the complete color scale vector that has been
  2033. // applied to this node via a previous call to
  2034. // set_color_scale() and/or set_alpha_scale(), or all
  2035. // 1's (identity) if no scale has been applied to this
  2036. // particular node.
  2037. ////////////////////////////////////////////////////////////////////
  2038. const LVecBase4f &NodePath::
  2039. get_color_scale() const {
  2040. static const LVecBase4f ident_scale(1.0f, 1.0f, 1.0f, 1.0f);
  2041. nassertr_always(!is_empty(), ident_scale);
  2042. const RenderAttrib *attrib =
  2043. node()->get_attrib(ColorScaleAttrib::get_class_type());
  2044. if (attrib != (const RenderAttrib *)NULL) {
  2045. const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attrib);
  2046. return csa->get_scale();
  2047. }
  2048. return ident_scale;
  2049. }
  2050. ////////////////////////////////////////////////////////////////////
  2051. // Function: NodePath::set_light
  2052. // Access: Published
  2053. // Description: Adds the indicated Light or PolylightNode to the list
  2054. // of lights that illuminate geometry at this node and
  2055. // below. The light itself should be parented into the
  2056. // scene graph elsewhere, to represent the light's
  2057. // position in space; but until set_light() is called it
  2058. // will illuminate no geometry.
  2059. ////////////////////////////////////////////////////////////////////
  2060. void NodePath::
  2061. set_light(const NodePath &light, int priority) {
  2062. nassertv_always(!is_empty());
  2063. if (!light.is_empty()) {
  2064. Light *light_obj = light.node()->as_light();
  2065. if (light_obj != (Light *)NULL) {
  2066. // It's an actual Light object.
  2067. const RenderAttrib *attrib =
  2068. node()->get_attrib(LightAttrib::get_class_type());
  2069. if (attrib != (const RenderAttrib *)NULL) {
  2070. priority = max(priority,
  2071. node()->get_state()->get_override(LightAttrib::get_class_type()));
  2072. const LightAttrib *la = DCAST(LightAttrib, attrib);
  2073. // Modify the existing LightAttrib to add the indicated
  2074. // light.
  2075. node()->set_attrib(la->add_on_light(light), priority);
  2076. } else {
  2077. // Create a new LightAttrib for this node.
  2078. CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make());
  2079. node()->set_attrib(la->add_on_light(light), priority);
  2080. }
  2081. return;
  2082. } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
  2083. // It's a Polylight object.
  2084. if (priority != 0) {
  2085. // PolylightEffects can't have a priority, since they're just
  2086. // an effect to be applied immediately.
  2087. pgraph_cat.warning()
  2088. << "Ignoring priority on set_light(" << light << ")\n";
  2089. }
  2090. const RenderEffect *effect =
  2091. node()->get_effect(PolylightEffect::get_class_type());
  2092. if (effect != (const RenderEffect *)NULL) {
  2093. const PolylightEffect *ple = DCAST(PolylightEffect, effect);
  2094. // Modify the existing PolylightEffect to add the indicated
  2095. // light.
  2096. node()->set_effect(ple->add_light(light));
  2097. } else {
  2098. // Create a new PolylightEffect for this node.
  2099. CPT(PolylightEffect) ple = DCAST(PolylightEffect, PolylightEffect::make());
  2100. node()->set_effect(ple->add_light(light));
  2101. }
  2102. return;
  2103. }
  2104. }
  2105. nassert_raise("Not a Light object.");
  2106. }
  2107. ////////////////////////////////////////////////////////////////////
  2108. // Function: NodePath::set_light_off
  2109. // Access: Published
  2110. // Description: Sets the geometry at this level and below to render
  2111. // using no lights at all. This is different
  2112. // from not specifying a light; rather, this
  2113. // specifically contradicts set_light() at a higher
  2114. // node level (or, with a priority, overrides a
  2115. // set_light() at a lower level).
  2116. //
  2117. // If no lights are in effect on a particular piece of
  2118. // geometry, that geometry is rendered with lighting
  2119. // disabled.
  2120. ////////////////////////////////////////////////////////////////////
  2121. void NodePath::
  2122. set_light_off(int priority) {
  2123. nassertv_always(!is_empty());
  2124. node()->set_attrib(LightAttrib::make_all_off(), priority);
  2125. node()->clear_effect(PolylightEffect::get_class_type());
  2126. }
  2127. ////////////////////////////////////////////////////////////////////
  2128. // Function: NodePath::set_light_off
  2129. // Access: Published
  2130. // Description: Sets the geometry at this level and below to render
  2131. // without using the indicated Light. This is different
  2132. // from not specifying the Light; rather, this
  2133. // specifically contradicts set_light() at a higher node
  2134. // level (or, with a priority, overrides a set_light()
  2135. // at a lower level).
  2136. //
  2137. // This interface does not support PolylightNodes, which
  2138. // cannot be turned off at a lower level.
  2139. ////////////////////////////////////////////////////////////////////
  2140. void NodePath::
  2141. set_light_off(const NodePath &light, int priority) {
  2142. nassertv_always(!is_empty());
  2143. if (!light.is_empty()) {
  2144. Light *light_obj = light.node()->as_light();
  2145. if (light_obj != (Light *)NULL) {
  2146. const RenderAttrib *attrib =
  2147. node()->get_attrib(LightAttrib::get_class_type());
  2148. if (attrib != (const RenderAttrib *)NULL) {
  2149. priority = max(priority,
  2150. node()->get_state()->get_override(LightAttrib::get_class_type()));
  2151. const LightAttrib *la = DCAST(LightAttrib, attrib);
  2152. // Modify the existing LightAttrib to add the indicated light
  2153. // to the "off" list. This also, incidentally, removes it from
  2154. // the "on" list if it is there.
  2155. node()->set_attrib(la->add_off_light(light), priority);
  2156. } else {
  2157. // Create a new LightAttrib for this node that turns off the
  2158. // indicated light.
  2159. CPT(LightAttrib) la = DCAST(LightAttrib, LightAttrib::make());
  2160. node()->set_attrib(la->add_off_light(light), priority);
  2161. }
  2162. return;
  2163. }
  2164. }
  2165. nassert_raise("Not a Light object.");
  2166. }
  2167. ////////////////////////////////////////////////////////////////////
  2168. // Function: NodePath::clear_light
  2169. // Access: Published
  2170. // Description: Completely removes any lighting operations that may
  2171. // have been set via set_light() or set_light_off()
  2172. // from this particular node.
  2173. ////////////////////////////////////////////////////////////////////
  2174. void NodePath::
  2175. clear_light() {
  2176. nassertv_always(!is_empty());
  2177. node()->clear_attrib(LightAttrib::get_class_type());
  2178. node()->clear_effect(PolylightEffect::get_class_type());
  2179. }
  2180. ////////////////////////////////////////////////////////////////////
  2181. // Function: NodePath::clear_light
  2182. // Access: Published
  2183. // Description: Removes any reference to the indicated Light or
  2184. // PolylightNode from the NodePath.
  2185. ////////////////////////////////////////////////////////////////////
  2186. void NodePath::
  2187. clear_light(const NodePath &light) {
  2188. nassertv_always(!is_empty());
  2189. if (!light.is_empty()) {
  2190. Light *light_obj = light.node()->as_light();
  2191. if (light_obj != (Light *)NULL) {
  2192. const RenderAttrib *attrib =
  2193. node()->get_attrib(LightAttrib::get_class_type());
  2194. if (attrib != (const RenderAttrib *)NULL) {
  2195. CPT(LightAttrib) la = DCAST(LightAttrib, attrib);
  2196. la = DCAST(LightAttrib, la->remove_on_light(light));
  2197. la = DCAST(LightAttrib, la->remove_off_light(light));
  2198. if (la->is_identity()) {
  2199. node()->clear_attrib(LightAttrib::get_class_type());
  2200. } else {
  2201. int priority = node()->get_state()->get_override(LightAttrib::get_class_type());
  2202. node()->set_attrib(la, priority);
  2203. }
  2204. }
  2205. return;
  2206. } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
  2207. const RenderEffect *effect =
  2208. node()->get_effect(PolylightEffect::get_class_type());
  2209. if (effect != (const RenderEffect *)NULL) {
  2210. CPT(PolylightEffect) ple = DCAST(PolylightEffect, effect);
  2211. ple = DCAST(PolylightEffect, ple->remove_light(light));
  2212. node()->set_effect(ple);
  2213. }
  2214. return;
  2215. }
  2216. }
  2217. nassert_raise("Not a Light object.");
  2218. }
  2219. ////////////////////////////////////////////////////////////////////
  2220. // Function: NodePath::has_light
  2221. // Access: Published
  2222. // Description: Returns true if the indicated Light or PolylightNode
  2223. // has been specifically enabled on this particular
  2224. // node. This means that someone called set_light() on
  2225. // this node with the indicated light.
  2226. ////////////////////////////////////////////////////////////////////
  2227. bool NodePath::
  2228. has_light(const NodePath &light) const {
  2229. nassertr_always(!is_empty(), false);
  2230. if (!light.is_empty()) {
  2231. Light *light_obj = light.node()->as_light();
  2232. if (light_obj != (Light *)NULL) {
  2233. const RenderAttrib *attrib =
  2234. node()->get_attrib(LightAttrib::get_class_type());
  2235. if (attrib != (const RenderAttrib *)NULL) {
  2236. const LightAttrib *la = DCAST(LightAttrib, attrib);
  2237. return la->has_on_light(light);
  2238. }
  2239. return false;
  2240. } else if (light.node()->is_of_type(PolylightNode::get_class_type())) {
  2241. const RenderEffect *effect =
  2242. node()->get_effect(PolylightEffect::get_class_type());
  2243. if (effect != (const RenderEffect *)NULL) {
  2244. const PolylightEffect *ple = DCAST(PolylightEffect, effect);
  2245. return ple->has_light(light);
  2246. }
  2247. return false;
  2248. }
  2249. }
  2250. nassert_raise("Not a Light object.");
  2251. return false;
  2252. }
  2253. ////////////////////////////////////////////////////////////////////
  2254. // Function: NodePath::has_light_off
  2255. // Access: Published
  2256. // Description: Returns true if all Lights have been specifically
  2257. // disabled on this particular node. This means that
  2258. // someone called set_light_off() on this node with no
  2259. // parameters.
  2260. ////////////////////////////////////////////////////////////////////
  2261. bool NodePath::
  2262. has_light_off() const {
  2263. nassertr_always(!is_empty(), false);
  2264. const RenderAttrib *attrib =
  2265. node()->get_attrib(LightAttrib::get_class_type());
  2266. if (attrib != (const RenderAttrib *)NULL) {
  2267. const LightAttrib *la = DCAST(LightAttrib, attrib);
  2268. return la->has_all_off();
  2269. }
  2270. return false;
  2271. }
  2272. ////////////////////////////////////////////////////////////////////
  2273. // Function: NodePath::has_light_off
  2274. // Access: Published
  2275. // Description: Returns true if the indicated Light has been
  2276. // specifically disabled on this particular node. This
  2277. // means that someone called set_light_off() on this
  2278. // node with the indicated light.
  2279. //
  2280. // This interface does not support PolylightNodes, which
  2281. // cannot be turned off at a lower level.
  2282. ////////////////////////////////////////////////////////////////////
  2283. bool NodePath::
  2284. has_light_off(const NodePath &light) const {
  2285. nassertr_always(!is_empty(), false);
  2286. if (!light.is_empty()) {
  2287. Light *light_obj = light.node()->as_light();
  2288. if (light_obj != (Light *)NULL) {
  2289. const RenderAttrib *attrib =
  2290. node()->get_attrib(LightAttrib::get_class_type());
  2291. if (attrib != (const RenderAttrib *)NULL) {
  2292. const LightAttrib *la = DCAST(LightAttrib, attrib);
  2293. return la->has_off_light(light);
  2294. }
  2295. }
  2296. }
  2297. nassert_raise("Not a Light object.");
  2298. return false;
  2299. }
  2300. ////////////////////////////////////////////////////////////////////
  2301. // Function: NodePath::set_clip_plane
  2302. // Access: Published
  2303. // Description: Adds the indicated clipping plane to the list of
  2304. // planes that apply to geometry at this node and below.
  2305. // The clipping plane itself, a PlaneNode, should be
  2306. // parented into the scene graph elsewhere, to represent
  2307. // the plane's position in space; but until
  2308. // set_clip_plane() is called it will clip no geometry.
  2309. ////////////////////////////////////////////////////////////////////
  2310. void NodePath::
  2311. set_clip_plane(const NodePath &clip_plane, int priority) {
  2312. nassertv_always(!is_empty());
  2313. if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
  2314. const RenderAttrib *attrib =
  2315. node()->get_attrib(ClipPlaneAttrib::get_class_type());
  2316. if (attrib != (const RenderAttrib *)NULL) {
  2317. priority = max(priority,
  2318. node()->get_state()->get_override(ClipPlaneAttrib::get_class_type()));
  2319. const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
  2320. // Modify the existing ClipPlaneAttrib to add the indicated
  2321. // clip_plane.
  2322. node()->set_attrib(la->add_on_plane(clip_plane), priority);
  2323. } else {
  2324. // Create a new ClipPlaneAttrib for this node.
  2325. CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
  2326. node()->set_attrib(la->add_on_plane(clip_plane), priority);
  2327. }
  2328. return;
  2329. }
  2330. nassert_raise("Not a PlaneNode object.");
  2331. }
  2332. ////////////////////////////////////////////////////////////////////
  2333. // Function: NodePath::set_clip_plane_off
  2334. // Access: Published
  2335. // Description: Sets the geometry at this level and below to render
  2336. // using no clip_planes at all. This is different
  2337. // from not specifying a clip_plane; rather, this
  2338. // specifically contradicts set_clip_plane() at a higher
  2339. // node level (or, with a priority, overrides a
  2340. // set_clip_plane() at a lower level).
  2341. //
  2342. // If no clip_planes are in effect on a particular piece
  2343. // of geometry, that geometry is rendered without being
  2344. // clipped (other than by the viewing frustum).
  2345. ////////////////////////////////////////////////////////////////////
  2346. void NodePath::
  2347. set_clip_plane_off(int priority) {
  2348. nassertv_always(!is_empty());
  2349. node()->set_attrib(ClipPlaneAttrib::make_all_off(), priority);
  2350. }
  2351. ////////////////////////////////////////////////////////////////////
  2352. // Function: NodePath::set_clip_plane_off
  2353. // Access: Published
  2354. // Description: Sets the geometry at this level and below to render
  2355. // without being clipped by the indicated PlaneNode.
  2356. // This is different from not specifying the PlaneNode;
  2357. // rather, this specifically contradicts
  2358. // set_clip_plane() at a higher node level (or, with a
  2359. // priority, overrides a set_clip_plane() at a lower
  2360. // level).
  2361. ////////////////////////////////////////////////////////////////////
  2362. void NodePath::
  2363. set_clip_plane_off(const NodePath &clip_plane, int priority) {
  2364. nassertv_always(!is_empty());
  2365. if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
  2366. const RenderAttrib *attrib =
  2367. node()->get_attrib(ClipPlaneAttrib::get_class_type());
  2368. if (attrib != (const RenderAttrib *)NULL) {
  2369. priority = max(priority,
  2370. node()->get_state()->get_override(ClipPlaneAttrib::get_class_type()));
  2371. const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
  2372. // Modify the existing ClipPlaneAttrib to add the indicated clip_plane
  2373. // to the "off" list. This also, incidentally, removes it from
  2374. // the "on" list if it is there.
  2375. node()->set_attrib(la->add_off_plane(clip_plane), priority);
  2376. } else {
  2377. // Create a new ClipPlaneAttrib for this node that turns off the
  2378. // indicated clip_plane.
  2379. CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, ClipPlaneAttrib::make());
  2380. node()->set_attrib(la->add_off_plane(clip_plane), priority);
  2381. }
  2382. return;
  2383. }
  2384. nassert_raise("Not a PlaneNode object.");
  2385. }
  2386. ////////////////////////////////////////////////////////////////////
  2387. // Function: NodePath::clear_clip_plane
  2388. // Access: Published
  2389. // Description: Completely removes any clip planes that may have been
  2390. // set via set_clip_plane() or set_clip_plane_off() from
  2391. // this particular node.
  2392. ////////////////////////////////////////////////////////////////////
  2393. void NodePath::
  2394. clear_clip_plane() {
  2395. nassertv_always(!is_empty());
  2396. node()->clear_attrib(ClipPlaneAttrib::get_class_type());
  2397. }
  2398. ////////////////////////////////////////////////////////////////////
  2399. // Function: NodePath::clear_clip_plane
  2400. // Access: Published
  2401. // Description: Removes any reference to the indicated clipping plane
  2402. // from the NodePath.
  2403. ////////////////////////////////////////////////////////////////////
  2404. void NodePath::
  2405. clear_clip_plane(const NodePath &clip_plane) {
  2406. nassertv_always(!is_empty());
  2407. if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
  2408. const RenderAttrib *attrib =
  2409. node()->get_attrib(ClipPlaneAttrib::get_class_type());
  2410. if (attrib != (const RenderAttrib *)NULL) {
  2411. CPT(ClipPlaneAttrib) la = DCAST(ClipPlaneAttrib, attrib);
  2412. la = DCAST(ClipPlaneAttrib, la->remove_on_plane(clip_plane));
  2413. la = DCAST(ClipPlaneAttrib, la->remove_off_plane(clip_plane));
  2414. if (la->is_identity()) {
  2415. node()->clear_attrib(ClipPlaneAttrib::get_class_type());
  2416. } else {
  2417. int priority = node()->get_state()->get_override(ClipPlaneAttrib::get_class_type());
  2418. node()->set_attrib(la, priority);
  2419. }
  2420. }
  2421. return;
  2422. }
  2423. nassert_raise("Not a PlaneNode object.");
  2424. }
  2425. ////////////////////////////////////////////////////////////////////
  2426. // Function: NodePath::has_clip_plane
  2427. // Access: Published
  2428. // Description: Returns true if the indicated clipping plane has been
  2429. // specifically applied to this particular node. This
  2430. // means that someone called set_clip_plane() on this
  2431. // node with the indicated clip_plane.
  2432. ////////////////////////////////////////////////////////////////////
  2433. bool NodePath::
  2434. has_clip_plane(const NodePath &clip_plane) const {
  2435. nassertr_always(!is_empty(), false);
  2436. if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
  2437. const RenderAttrib *attrib =
  2438. node()->get_attrib(ClipPlaneAttrib::get_class_type());
  2439. if (attrib != (const RenderAttrib *)NULL) {
  2440. const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
  2441. return la->has_on_plane(clip_plane);
  2442. }
  2443. return false;
  2444. }
  2445. nassert_raise("Not a PlaneNode object.");
  2446. return false;
  2447. }
  2448. ////////////////////////////////////////////////////////////////////
  2449. // Function: NodePath::has_clip_plane_off
  2450. // Access: Published
  2451. // Description: Returns true if all clipping planes have been
  2452. // specifically disabled on this particular node. This
  2453. // means that someone called set_clip_plane_off() on
  2454. // this node with no parameters.
  2455. ////////////////////////////////////////////////////////////////////
  2456. bool NodePath::
  2457. has_clip_plane_off() const {
  2458. nassertr_always(!is_empty(), false);
  2459. const RenderAttrib *attrib =
  2460. node()->get_attrib(ClipPlaneAttrib::get_class_type());
  2461. if (attrib != (const RenderAttrib *)NULL) {
  2462. const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
  2463. return la->has_all_off();
  2464. }
  2465. return false;
  2466. }
  2467. ////////////////////////////////////////////////////////////////////
  2468. // Function: NodePath::has_clip_plane_off
  2469. // Access: Published
  2470. // Description: Returns true if the indicated clipping plane has been
  2471. // specifically disabled on this particular node. This
  2472. // means that someone called set_clip_plane_off() on
  2473. // this node with the indicated clip_plane.
  2474. ////////////////////////////////////////////////////////////////////
  2475. bool NodePath::
  2476. has_clip_plane_off(const NodePath &clip_plane) const {
  2477. nassertr_always(!is_empty(), false);
  2478. if (!clip_plane.is_empty() && clip_plane.node()->is_of_type(PlaneNode::get_class_type())) {
  2479. const RenderAttrib *attrib =
  2480. node()->get_attrib(ClipPlaneAttrib::get_class_type());
  2481. if (attrib != (const RenderAttrib *)NULL) {
  2482. const ClipPlaneAttrib *la = DCAST(ClipPlaneAttrib, attrib);
  2483. return la->has_off_plane(clip_plane);
  2484. }
  2485. }
  2486. nassert_raise("Not a PlaneNode object.");
  2487. return false;
  2488. }
  2489. ////////////////////////////////////////////////////////////////////
  2490. // Function: NodePath::set_bin
  2491. // Access: Published
  2492. // Description: Assigns the geometry at this level and below to the
  2493. // named rendering bin. It is the user's responsibility
  2494. // to ensure that such a bin already exists, either via
  2495. // the cull-bin Configrc variable, or by explicitly
  2496. // creating a GeomBin of the appropriate type at
  2497. // runtime.
  2498. //
  2499. // There are two default bins created when Panda is
  2500. // started: "default" and "fixed". Normally, all
  2501. // geometry is assigned to "default" unless specified
  2502. // otherwise. This bin renders opaque geometry in
  2503. // state-sorted order, followed by transparent geometry
  2504. // sorted back-to-front. If any geometry is assigned to
  2505. // "fixed", this will be rendered following all the
  2506. // geometry in "default", in the order specified by
  2507. // draw_order for each piece of geometry so assigned.
  2508. //
  2509. // The draw_order parameter is meaningful only for
  2510. // GeomBinFixed type bins, e.g. "fixed". Other kinds of
  2511. // bins ignore it.
  2512. ////////////////////////////////////////////////////////////////////
  2513. void NodePath::
  2514. set_bin(const string &bin_name, int draw_order, int priority) {
  2515. nassertv_always(!is_empty());
  2516. node()->set_attrib(CullBinAttrib::make(bin_name, draw_order), priority);
  2517. }
  2518. ////////////////////////////////////////////////////////////////////
  2519. // Function: NodePath::clear_bin
  2520. // Access: Published
  2521. // Description: Completely removes any bin adjustment that may have
  2522. // been set via set_bin() from this particular node.
  2523. ////////////////////////////////////////////////////////////////////
  2524. void NodePath::
  2525. clear_bin() {
  2526. nassertv_always(!is_empty());
  2527. node()->clear_attrib(CullBinAttrib::get_class_type());
  2528. }
  2529. ////////////////////////////////////////////////////////////////////
  2530. // Function: NodePath::has_bin
  2531. // Access: Published
  2532. // Description: Returns true if the node has been assigned to the a
  2533. // particular rendering bin via set_bin(), false
  2534. // otherwise.
  2535. ////////////////////////////////////////////////////////////////////
  2536. bool NodePath::
  2537. has_bin() const {
  2538. nassertr_always(!is_empty(), false);
  2539. return node()->has_attrib(CullBinAttrib::get_class_type());
  2540. }
  2541. ////////////////////////////////////////////////////////////////////
  2542. // Function: NodePath::get_bin_name
  2543. // Access: Published
  2544. // Description: Returns the name of the bin that this particular node
  2545. // was assigned to via set_bin(), or the empty string if
  2546. // no bin was assigned. See set_bin() and has_bin().
  2547. ////////////////////////////////////////////////////////////////////
  2548. string NodePath::
  2549. get_bin_name() const {
  2550. nassertr_always(!is_empty(), string());
  2551. const RenderAttrib *attrib =
  2552. node()->get_attrib(CullBinAttrib::get_class_type());
  2553. if (attrib != (const RenderAttrib *)NULL) {
  2554. const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
  2555. return ba->get_bin_name();
  2556. }
  2557. return string();
  2558. }
  2559. ////////////////////////////////////////////////////////////////////
  2560. // Function: NodePath::get_bin_draw_order
  2561. // Access: Published
  2562. // Description: Returns the drawing order associated with the bin
  2563. // that this particular node was assigned to via
  2564. // set_bin(), or 0 if no bin was assigned. See
  2565. // set_bin() and has_bin().
  2566. ////////////////////////////////////////////////////////////////////
  2567. int NodePath::
  2568. get_bin_draw_order() const {
  2569. nassertr_always(!is_empty(), false);
  2570. const RenderAttrib *attrib =
  2571. node()->get_attrib(CullBinAttrib::get_class_type());
  2572. if (attrib != (const RenderAttrib *)NULL) {
  2573. const CullBinAttrib *ba = DCAST(CullBinAttrib, attrib);
  2574. return ba->get_draw_order();
  2575. }
  2576. return 0;
  2577. }
  2578. ////////////////////////////////////////////////////////////////////
  2579. // Function: NodePath::set_texture
  2580. // Access: Published
  2581. // Description: Adds the indicated texture to the list of textures
  2582. // that will be rendered on the default texture stage.
  2583. //
  2584. // This is the deprecated single-texture variant of this
  2585. // method; it is now superceded by set_texture() that
  2586. // accepts a stage and texture. However, this method
  2587. // may be used in the presence of multitexture if you
  2588. // just want to adjust the default stage.
  2589. ////////////////////////////////////////////////////////////////////
  2590. void NodePath::
  2591. set_texture(Texture *tex, int priority) {
  2592. nassertv_always(!is_empty());
  2593. PT(TextureStage) stage = TextureStage::get_default();
  2594. set_texture(stage, tex, priority);
  2595. }
  2596. ////////////////////////////////////////////////////////////////////
  2597. // Function: NodePath::set_texture
  2598. // Access: Published
  2599. // Description: Adds the indicated texture to the list of textures
  2600. // that will be rendered on the indicated multitexture
  2601. // stage. If there are multiple texture stages
  2602. // specified (possibly on multiple different nodes at
  2603. // different levels), they will all be applied to
  2604. // geometry together, according to the stage
  2605. // specification set up in the TextureStage object.
  2606. ////////////////////////////////////////////////////////////////////
  2607. void NodePath::
  2608. set_texture(TextureStage *stage, Texture *tex, int priority) {
  2609. nassertv_always(!is_empty());
  2610. const RenderAttrib *attrib =
  2611. node()->get_attrib(TextureAttrib::get_class_type());
  2612. if (attrib != (const RenderAttrib *)NULL) {
  2613. priority = max(priority,
  2614. node()->get_state()->get_override(TextureAttrib::get_class_type()));
  2615. const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
  2616. // Modify the existing TextureAttrib to add the indicated
  2617. // texture.
  2618. node()->set_attrib(tsa->add_on_stage(stage, tex), priority);
  2619. } else {
  2620. // Create a new TextureAttrib for this node.
  2621. CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
  2622. node()->set_attrib(tsa->add_on_stage(stage, tex), priority);
  2623. }
  2624. }
  2625. ////////////////////////////////////////////////////////////////////
  2626. // Function: NodePath::set_texture_off
  2627. // Access: Published
  2628. // Description: Sets the geometry at this level and below to render
  2629. // using no texture, on any stage. This is different
  2630. // from not specifying a texture; rather, this
  2631. // specifically contradicts set_texture() at a higher
  2632. // node level (or, with a priority, overrides a
  2633. // set_texture() at a lower level).
  2634. ////////////////////////////////////////////////////////////////////
  2635. void NodePath::
  2636. set_texture_off(int priority) {
  2637. nassertv_always(!is_empty());
  2638. node()->set_attrib(TextureAttrib::make_all_off(), priority);
  2639. }
  2640. ////////////////////////////////////////////////////////////////////
  2641. // Function: NodePath::set_texture_off
  2642. // Access: Published
  2643. // Description: Sets the geometry at this level and below to render
  2644. // using no texture, on the indicated stage. This is
  2645. // different from not specifying a texture; rather, this
  2646. // specifically contradicts set_texture() at a higher
  2647. // node level (or, with a priority, overrides a
  2648. // set_texture() at a lower level).
  2649. ////////////////////////////////////////////////////////////////////
  2650. void NodePath::
  2651. set_texture_off(TextureStage *stage, int priority) {
  2652. nassertv_always(!is_empty());
  2653. const RenderAttrib *attrib =
  2654. node()->get_attrib(TextureAttrib::get_class_type());
  2655. if (attrib != (const RenderAttrib *)NULL) {
  2656. priority = max(priority,
  2657. node()->get_state()->get_override(TextureAttrib::get_class_type()));
  2658. const TextureAttrib *tsa = DCAST(TextureAttrib, attrib);
  2659. // Modify the existing TextureAttrib to add the indicated texture
  2660. // to the "off" list. This also, incidentally, removes it from
  2661. // the "on" list if it is there.
  2662. node()->set_attrib(tsa->add_off_stage(stage), priority);
  2663. } else {
  2664. // Create a new TextureAttrib for this node that turns off the
  2665. // indicated stage.
  2666. CPT(TextureAttrib) tsa = DCAST(TextureAttrib, TextureAttrib::make());
  2667. node()->set_attrib(tsa->add_off_stage(stage), priority);
  2668. }
  2669. }
  2670. ////////////////////////////////////////////////////////////////////
  2671. // Function: NodePath::clear_texture
  2672. // Access: Published
  2673. // Description: Completely removes any texture adjustment that may
  2674. // have been set via set_texture() or set_texture_off()
  2675. // from this particular node. This allows whatever
  2676. // textures might be otherwise affecting the geometry to
  2677. // show instead.
  2678. ////////////////////////////////////////////////////////////////////
  2679. void NodePath::
  2680. clear_texture() {
  2681. nassertv_always(!is_empty());
  2682. node()->clear_attrib(TextureAttrib::get_class_type());
  2683. }
  2684. ////////////////////////////////////////////////////////////////////
  2685. // Function: NodePath::clear_texture
  2686. // Access: Published
  2687. // Description: Removes any reference to the indicated texture stage
  2688. // from the NodePath.
  2689. ////////////////////////////////////////////////////////////////////
  2690. void NodePath::
  2691. clear_texture(TextureStage *stage) {
  2692. nassertv_always(!is_empty());
  2693. const RenderAttrib *attrib =
  2694. node()->get_attrib(TextureAttrib::get_class_type());
  2695. if (attrib != (const RenderAttrib *)NULL) {
  2696. CPT(TextureAttrib) tsa = DCAST(TextureAttrib, attrib);
  2697. tsa = DCAST(TextureAttrib, tsa->remove_on_stage(stage));
  2698. tsa = DCAST(TextureAttrib, tsa->remove_off_stage(stage));
  2699. if (tsa->is_identity()) {
  2700. node()->clear_attrib(TextureAttrib::get_class_type());
  2701. } else {
  2702. int priority = node()->get_state()->get_override(TextureAttrib::get_class_type());
  2703. node()->set_attrib(tsa, priority);
  2704. }
  2705. }
  2706. }
  2707. ////////////////////////////////////////////////////////////////////
  2708. // Function: NodePath::has_texture
  2709. // Access: Published
  2710. // Description: Returns true if a texture has been applied to this
  2711. // particular node via set_texture(), false otherwise.
  2712. // This is not the same thing as asking whether the
  2713. // geometry at this node will be rendered with
  2714. // texturing, as there may be a texture in effect from a
  2715. // higher or lower level.
  2716. ////////////////////////////////////////////////////////////////////
  2717. bool NodePath::
  2718. has_texture() const {
  2719. return get_texture() != (Texture *)NULL;
  2720. }
  2721. ////////////////////////////////////////////////////////////////////
  2722. // Function: NodePath::has_texture
  2723. // Access: Published
  2724. // Description: Returns true if texturing has been specifically
  2725. // enabled on this particular node for the indicated
  2726. // stage. This means that someone called
  2727. // set_texture() on this node with the indicated stage
  2728. // name, or the stage_name is the default stage_name,
  2729. // and someone called set_texture() on this node.
  2730. ////////////////////////////////////////////////////////////////////
  2731. bool NodePath::
  2732. has_texture(TextureStage *stage) const {
  2733. nassertr_always(!is_empty(), false);
  2734. const RenderAttrib *attrib =
  2735. node()->get_attrib(TextureAttrib::get_class_type());
  2736. if (attrib != (const RenderAttrib *)NULL) {
  2737. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  2738. return ta->has_on_stage(stage);
  2739. }
  2740. return false;
  2741. }
  2742. ////////////////////////////////////////////////////////////////////
  2743. // Function: NodePath::has_texture_off
  2744. // Access: Published
  2745. // Description: Returns true if texturing has been specifically
  2746. // disabled on this particular node via
  2747. // set_texture_off(), false otherwise. This is not the
  2748. // same thing as asking whether the geometry at this
  2749. // node will be rendered untextured, as there may be a
  2750. // texture in effect from a higher or lower level.
  2751. ////////////////////////////////////////////////////////////////////
  2752. bool NodePath::
  2753. has_texture_off() const {
  2754. nassertr_always(!is_empty(), false);
  2755. const RenderAttrib *attrib =
  2756. node()->get_attrib(TextureAttrib::get_class_type());
  2757. if (attrib != (const RenderAttrib *)NULL) {
  2758. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  2759. return ta->has_all_off();
  2760. }
  2761. return false;
  2762. }
  2763. ////////////////////////////////////////////////////////////////////
  2764. // Function: NodePath::has_texture_off
  2765. // Access: Published
  2766. // Description: Returns true if texturing has been specifically
  2767. // disabled on this particular node for the indicated
  2768. // stage. This means that someone called
  2769. // set_texture_off() on this node with the indicated
  2770. // stage name, or that someone called set_texture_off()
  2771. // on this node to remove all stages.
  2772. ////////////////////////////////////////////////////////////////////
  2773. bool NodePath::
  2774. has_texture_off(TextureStage *stage) const {
  2775. nassertr_always(!is_empty(), false);
  2776. const RenderAttrib *attrib =
  2777. node()->get_attrib(TextureAttrib::get_class_type());
  2778. if (attrib != (const RenderAttrib *)NULL) {
  2779. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  2780. return ta->has_off_stage(stage);
  2781. }
  2782. return false;
  2783. }
  2784. ////////////////////////////////////////////////////////////////////
  2785. // Function: NodePath::get_texture
  2786. // Access: Published
  2787. // Description: Returns the base-level texture that has been set on
  2788. // this particular node, or NULL if no texture has been
  2789. // set. This is not necessarily the texture that will
  2790. // be applied to the geometry at or below this level, as
  2791. // another texture at a higher or lower level may
  2792. // override.
  2793. //
  2794. // See also find_texture().
  2795. ////////////////////////////////////////////////////////////////////
  2796. Texture *NodePath::
  2797. get_texture() const {
  2798. nassertr_always(!is_empty(), NULL);
  2799. const RenderAttrib *attrib =
  2800. node()->get_attrib(TextureAttrib::get_class_type());
  2801. if (attrib != (const RenderAttrib *)NULL) {
  2802. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  2803. return ta->get_texture();
  2804. }
  2805. return NULL;
  2806. }
  2807. ////////////////////////////////////////////////////////////////////
  2808. // Function: NodePath::get_texture
  2809. // Access: Published
  2810. // Description: Returns the texture that has been set on the
  2811. // indicated stage for this particular node, or NULL if
  2812. // no texture has been set for this stage.
  2813. ////////////////////////////////////////////////////////////////////
  2814. Texture *NodePath::
  2815. get_texture(TextureStage *stage) const {
  2816. nassertr_always(!is_empty(), NULL);
  2817. const RenderAttrib *attrib =
  2818. node()->get_attrib(TextureAttrib::get_class_type());
  2819. if (attrib != (const RenderAttrib *)NULL) {
  2820. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  2821. return ta->get_on_texture(stage);
  2822. }
  2823. return NULL;
  2824. }
  2825. ////////////////////////////////////////////////////////////////////
  2826. // Function: NodePath::set_shader
  2827. // Access: Published
  2828. // Description:
  2829. ////////////////////////////////////////////////////////////////////
  2830. void NodePath::
  2831. set_shader(const Shader *sha, int priority) {
  2832. nassertv_always(!is_empty());
  2833. const RenderAttrib *attrib =
  2834. node()->get_attrib(ShaderAttrib::get_class_type());
  2835. if (attrib != (const RenderAttrib *)NULL) {
  2836. priority = max(priority,
  2837. node()->get_state()->get_override(ShaderAttrib::get_class_type()));
  2838. const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
  2839. node()->set_attrib(sa->set_shader(sha, priority));
  2840. } else {
  2841. // Create a new ShaderAttrib for this node.
  2842. CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
  2843. node()->set_attrib(sa->set_shader(sha, priority));
  2844. }
  2845. }
  2846. ////////////////////////////////////////////////////////////////////
  2847. // Function: NodePath::set_shader_off
  2848. // Access: Published
  2849. // Description:
  2850. ////////////////////////////////////////////////////////////////////
  2851. void NodePath::
  2852. set_shader_off(int priority) {
  2853. set_shader(NULL, priority);
  2854. }
  2855. ////////////////////////////////////////////////////////////////////
  2856. // Function: NodePath::clear_shader
  2857. // Access: Published
  2858. // Description:
  2859. ////////////////////////////////////////////////////////////////////
  2860. void NodePath::
  2861. clear_shader() {
  2862. nassertv_always(!is_empty());
  2863. const RenderAttrib *attrib =
  2864. node()->get_attrib(ShaderAttrib::get_class_type());
  2865. if (attrib != (const RenderAttrib *)NULL) {
  2866. const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
  2867. node()->set_attrib(sa->clear_shader());
  2868. }
  2869. }
  2870. ////////////////////////////////////////////////////////////////////
  2871. // Function: NodePath::get_shader
  2872. // Access: Published
  2873. // Description:
  2874. ////////////////////////////////////////////////////////////////////
  2875. const Shader *NodePath::
  2876. get_shader() const {
  2877. nassertr_always(!is_empty(), NULL);
  2878. const RenderAttrib *attrib =
  2879. node()->get_attrib(ShaderAttrib::get_class_type());
  2880. if (attrib != (const RenderAttrib *)NULL) {
  2881. const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
  2882. return sa->get_shader();
  2883. }
  2884. return NULL;
  2885. }
  2886. ////////////////////////////////////////////////////////////////////
  2887. // Function: NodePath::set_shader_input
  2888. // Access: Published
  2889. // Description:
  2890. ////////////////////////////////////////////////////////////////////
  2891. void NodePath::
  2892. set_shader_input(const ShaderInput *inp) {
  2893. nassertv_always(!is_empty());
  2894. const RenderAttrib *attrib =
  2895. node()->get_attrib(ShaderAttrib::get_class_type());
  2896. if (attrib != (const RenderAttrib *)NULL) {
  2897. const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
  2898. node()->set_attrib(sa->set_shader_input(inp));
  2899. } else {
  2900. // Create a new ShaderAttrib for this node.
  2901. CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make());
  2902. node()->set_attrib(sa->set_shader_input(inp));
  2903. }
  2904. }
  2905. ////////////////////////////////////////////////////////////////////
  2906. // Function: NodePath::get_shader_input
  2907. // Access: Published
  2908. // Description:
  2909. ////////////////////////////////////////////////////////////////////
  2910. const ShaderInput *NodePath::
  2911. get_shader_input(InternalName *id) const {
  2912. nassertr_always(!is_empty(), NULL);
  2913. const RenderAttrib *attrib =
  2914. node()->get_attrib(ShaderAttrib::get_class_type());
  2915. if (attrib != (const RenderAttrib *)NULL) {
  2916. const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
  2917. return sa->get_shader_input(id);
  2918. }
  2919. return NULL;
  2920. }
  2921. ////////////////////////////////////////////////////////////////////
  2922. // Function: NodePath::clear_shader_input
  2923. // Access: Published
  2924. // Description:
  2925. ////////////////////////////////////////////////////////////////////
  2926. void NodePath::
  2927. clear_shader_input(InternalName *id) {
  2928. nassertv_always(!is_empty());
  2929. const RenderAttrib *attrib =
  2930. node()->get_attrib(ShaderAttrib::get_class_type());
  2931. if (attrib != (const RenderAttrib *)NULL) {
  2932. const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib);
  2933. node()->set_attrib(sa->clear_shader_input(id));
  2934. }
  2935. }
  2936. ////////////////////////////////////////////////////////////////////
  2937. // Function: NodePath::set_shader_input
  2938. // Access: Published
  2939. // Description:
  2940. ////////////////////////////////////////////////////////////////////
  2941. void NodePath::
  2942. set_shader_input(InternalName *id, Texture *tex, int priority) {
  2943. set_shader_input(new ShaderInput(id,tex,priority));
  2944. }
  2945. ////////////////////////////////////////////////////////////////////
  2946. // Function: NodePath::set_shader_input
  2947. // Access: Published
  2948. // Description:
  2949. ////////////////////////////////////////////////////////////////////
  2950. void NodePath::
  2951. set_shader_input(InternalName *id, const NodePath &np, int priority) {
  2952. set_shader_input(new ShaderInput(id,np,priority));
  2953. }
  2954. ////////////////////////////////////////////////////////////////////
  2955. // Function: NodePath::set_shader_input
  2956. // Access: Published
  2957. // Description:
  2958. ////////////////////////////////////////////////////////////////////
  2959. void NodePath::
  2960. set_shader_input(InternalName *id, const LVector4f &v, int priority) {
  2961. set_shader_input(new ShaderInput(id,v,priority));
  2962. }
  2963. ////////////////////////////////////////////////////////////////////
  2964. // Function: NodePath::set_shader_input
  2965. // Access: Published
  2966. // Description:
  2967. ////////////////////////////////////////////////////////////////////
  2968. void NodePath::
  2969. set_shader_input(InternalName *id, double n1, double n2, double n3, double n4, int priority) {
  2970. set_shader_input(new ShaderInput(id,LVector4f(n1,n2,n3,n4),priority));
  2971. }
  2972. ////////////////////////////////////////////////////////////////////
  2973. // Function: NodePath::set_shader_input
  2974. // Access: Published
  2975. // Description:
  2976. ////////////////////////////////////////////////////////////////////
  2977. void NodePath::
  2978. set_shader_input(const string &id, Texture *tex, int priority) {
  2979. set_shader_input(new ShaderInput(InternalName::make(id),tex,priority));
  2980. }
  2981. ////////////////////////////////////////////////////////////////////
  2982. // Function: NodePath::set_shader_input
  2983. // Access: Published
  2984. // Description:
  2985. ////////////////////////////////////////////////////////////////////
  2986. void NodePath::
  2987. set_shader_input(const string &id, const NodePath &np, int priority) {
  2988. set_shader_input(new ShaderInput(InternalName::make(id),np,priority));
  2989. }
  2990. ////////////////////////////////////////////////////////////////////
  2991. // Function: NodePath::set_shader_input
  2992. // Access: Published
  2993. // Description:
  2994. ////////////////////////////////////////////////////////////////////
  2995. void NodePath::
  2996. set_shader_input(const string &id, const LVector4f &v, int priority) {
  2997. set_shader_input(new ShaderInput(InternalName::make(id),v,priority));
  2998. }
  2999. ////////////////////////////////////////////////////////////////////
  3000. // Function: NodePath::set_shader_input
  3001. // Access: Published
  3002. // Description:
  3003. ////////////////////////////////////////////////////////////////////
  3004. void NodePath::
  3005. set_shader_input(const string &id, double n1, double n2, double n3, double n4, int priority) {
  3006. set_shader_input(new ShaderInput(InternalName::make(id),LVector4f(n1,n2,n3,n4),priority));
  3007. }
  3008. ////////////////////////////////////////////////////////////////////
  3009. // Function: NodePath::get_shader_input
  3010. // Access: Published
  3011. // Description:
  3012. ////////////////////////////////////////////////////////////////////
  3013. const ShaderInput *NodePath::
  3014. get_shader_input(const string &id) const {
  3015. return get_shader_input(InternalName::make(id));
  3016. }
  3017. ////////////////////////////////////////////////////////////////////
  3018. // Function: NodePath::clear_shader_input
  3019. // Access: Published
  3020. // Description:
  3021. ////////////////////////////////////////////////////////////////////
  3022. void NodePath::
  3023. clear_shader_input(const string &id) {
  3024. clear_shader_input(InternalName::make(id));
  3025. }
  3026. ////////////////////////////////////////////////////////////////////
  3027. // Function: NodePath::set_tex_transform
  3028. // Access: Published
  3029. // Description: Sets the texture matrix on the current node to the
  3030. // indicated transform for the given stage.
  3031. ////////////////////////////////////////////////////////////////////
  3032. void NodePath::
  3033. set_tex_transform(TextureStage *stage, const TransformState *transform) {
  3034. nassertv_always(!is_empty());
  3035. const RenderAttrib *attrib =
  3036. node()->get_attrib(TexMatrixAttrib::get_class_type());
  3037. if (attrib != (const RenderAttrib *)NULL) {
  3038. const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
  3039. // Modify the existing TexMatrixAttrib to add the indicated
  3040. // stage.
  3041. node()->set_attrib(tma->add_stage(stage, transform));
  3042. } else {
  3043. // Create a new TexMatrixAttrib for this node.
  3044. node()->set_attrib(TexMatrixAttrib::make(stage, transform));
  3045. }
  3046. }
  3047. ////////////////////////////////////////////////////////////////////
  3048. // Function: NodePath::clear_tex_transform
  3049. // Access: Published
  3050. // Description: Removes all texture matrices from the current node.
  3051. ////////////////////////////////////////////////////////////////////
  3052. void NodePath::
  3053. clear_tex_transform() {
  3054. nassertv_always(!is_empty());
  3055. node()->clear_attrib(TexMatrixAttrib::get_class_type());
  3056. }
  3057. ////////////////////////////////////////////////////////////////////
  3058. // Function: NodePath::clear_tex_transform
  3059. // Access: Published
  3060. // Description: Removes the texture matrix on the current node for
  3061. // the given stage.
  3062. ////////////////////////////////////////////////////////////////////
  3063. void NodePath::
  3064. clear_tex_transform(TextureStage *stage) {
  3065. nassertv_always(!is_empty());
  3066. const RenderAttrib *attrib =
  3067. node()->get_attrib(TexMatrixAttrib::get_class_type());
  3068. if (attrib != (const RenderAttrib *)NULL) {
  3069. CPT(TexMatrixAttrib) tma = DCAST(TexMatrixAttrib, attrib);
  3070. tma = DCAST(TexMatrixAttrib, tma->remove_stage(stage));
  3071. if (tma->is_empty()) {
  3072. node()->clear_attrib(TexMatrixAttrib::get_class_type());
  3073. } else {
  3074. node()->set_attrib(tma);
  3075. }
  3076. }
  3077. }
  3078. ////////////////////////////////////////////////////////////////////
  3079. // Function: NodePath::has_tex_transform
  3080. // Access: Published
  3081. // Description: Returns true if there is an explicit texture matrix
  3082. // on the current node for the given stage.
  3083. ////////////////////////////////////////////////////////////////////
  3084. bool NodePath::
  3085. has_tex_transform(TextureStage *stage) const {
  3086. nassertr_always(!is_empty(), false);
  3087. const RenderAttrib *attrib =
  3088. node()->get_attrib(TexMatrixAttrib::get_class_type());
  3089. if (attrib != (const RenderAttrib *)NULL) {
  3090. const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
  3091. return tma->has_stage(stage);
  3092. }
  3093. return false;
  3094. }
  3095. ////////////////////////////////////////////////////////////////////
  3096. // Function: NodePath::get_tex_transform
  3097. // Access: Published
  3098. // Description: Returns the texture matrix on the current node for the
  3099. // given stage, or identity transform if there is no
  3100. // explicit transform set for the given stage.
  3101. ////////////////////////////////////////////////////////////////////
  3102. CPT(TransformState) NodePath::
  3103. get_tex_transform(TextureStage *stage) const {
  3104. nassertr_always(!is_empty(), NULL);
  3105. const RenderAttrib *attrib =
  3106. node()->get_attrib(TexMatrixAttrib::get_class_type());
  3107. if (attrib != (const RenderAttrib *)NULL) {
  3108. const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
  3109. return tma->get_transform(stage);
  3110. }
  3111. return TransformState::make_identity();
  3112. }
  3113. ////////////////////////////////////////////////////////////////////
  3114. // Function: NodePath::set_tex_transform
  3115. // Access: Published
  3116. // Description: Sets the texture matrix on the current node to the
  3117. // indicated transform for the given stage.
  3118. ////////////////////////////////////////////////////////////////////
  3119. void NodePath::
  3120. set_tex_transform(const NodePath &other, TextureStage *stage, const TransformState *transform) {
  3121. nassertv(_error_type == ET_ok && other._error_type == ET_ok);
  3122. nassertv_always(!is_empty());
  3123. CPT(RenderState) state = get_state(other);
  3124. const RenderAttrib *attrib =
  3125. state->get_attrib(TexMatrixAttrib::get_class_type());
  3126. if (attrib != (const RenderAttrib *)NULL) {
  3127. const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
  3128. // Modify the existing TexMatrixAttrib to add the indicated
  3129. // stage.
  3130. state = state->add_attrib(tma->add_stage(stage, transform));
  3131. } else {
  3132. // Create a new TexMatrixAttrib for this node.
  3133. state = state->add_attrib(TexMatrixAttrib::make(stage, transform));
  3134. }
  3135. // Now compose that with our parent's state.
  3136. CPT(RenderState) rel_state;
  3137. if (has_parent()) {
  3138. rel_state = other.get_state(get_parent());
  3139. } else {
  3140. rel_state = other.get_state(NodePath());
  3141. }
  3142. CPT(RenderState) new_state = rel_state->compose(state);
  3143. // And apply only the TexMatrixAttrib to the current node, leaving
  3144. // the others unchanged.
  3145. node()->set_attrib(new_state->get_attrib(TexMatrixAttrib::get_class_type()));
  3146. }
  3147. ////////////////////////////////////////////////////////////////////
  3148. // Function: NodePath::get_tex_transform
  3149. // Access: Published
  3150. // Description: Returns the texture matrix on the current node for the
  3151. // given stage, relative to the other node.
  3152. ////////////////////////////////////////////////////////////////////
  3153. CPT(TransformState) NodePath::
  3154. get_tex_transform(const NodePath &other, TextureStage *stage) const {
  3155. nassertr(_error_type == ET_ok && other._error_type == ET_ok, TransformState::make_identity());
  3156. CPT(RenderState) state = get_state(other);
  3157. const RenderAttrib *attrib =
  3158. state->get_attrib(TexMatrixAttrib::get_class_type());
  3159. if (attrib != (const RenderAttrib *)NULL) {
  3160. const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, attrib);
  3161. return tma->get_transform(stage);
  3162. }
  3163. return TransformState::make_identity();
  3164. }
  3165. ////////////////////////////////////////////////////////////////////
  3166. // Function: NodePath::set_tex_gen
  3167. // Access: Published
  3168. // Description: Enables automatic texture coordinate generation for
  3169. // the indicated texture stage.
  3170. ////////////////////////////////////////////////////////////////////
  3171. void NodePath::
  3172. set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode, int priority) {
  3173. nassertv_always(!is_empty());
  3174. const RenderAttrib *attrib =
  3175. node()->get_attrib(TexGenAttrib::get_class_type());
  3176. CPT(TexGenAttrib) tga;
  3177. if (attrib != (const RenderAttrib *)NULL) {
  3178. priority = max(priority,
  3179. node()->get_state()->get_override(TextureAttrib::get_class_type()));
  3180. tga = DCAST(TexGenAttrib, attrib);
  3181. } else {
  3182. tga = DCAST(TexGenAttrib, TexGenAttrib::make());
  3183. }
  3184. node()->set_attrib(tga->add_stage(stage, mode), priority);
  3185. }
  3186. ////////////////////////////////////////////////////////////////////
  3187. // Function: NodePath::set_tex_gen
  3188. // Access: Published
  3189. // Description: Enables automatic texture coordinate generation for
  3190. // the indicated texture stage. This version of this
  3191. // method is useful when setting M_light_vector, which
  3192. // requires the name of the texture coordinate set that
  3193. // supplies the tangent and binormal, as well as the
  3194. // specific light to generate coordinates for.
  3195. ////////////////////////////////////////////////////////////////////
  3196. void NodePath::
  3197. set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode,
  3198. const string &source_name, const NodePath &light, int priority) {
  3199. nassertv_always(!is_empty());
  3200. const RenderAttrib *attrib =
  3201. node()->get_attrib(TexGenAttrib::get_class_type());
  3202. CPT(TexGenAttrib) tga;
  3203. if (attrib != (const RenderAttrib *)NULL) {
  3204. priority = max(priority,
  3205. node()->get_state()->get_override(TextureAttrib::get_class_type()));
  3206. tga = DCAST(TexGenAttrib, attrib);
  3207. } else {
  3208. tga = DCAST(TexGenAttrib, TexGenAttrib::make());
  3209. }
  3210. node()->set_attrib(tga->add_stage(stage, mode, source_name, light), priority);
  3211. }
  3212. ////////////////////////////////////////////////////////////////////
  3213. // Function: NodePath::set_tex_gen
  3214. // Access: Published
  3215. // Description: Enables automatic texture coordinate generation for
  3216. // the indicated texture stage. This version of this
  3217. // method is useful when setting M_constant, which
  3218. // requires a constant texture coordinate value.
  3219. ////////////////////////////////////////////////////////////////////
  3220. void NodePath::
  3221. set_tex_gen(TextureStage *stage, RenderAttrib::TexGenMode mode,
  3222. const TexCoord3f &constant_value, int priority) {
  3223. nassertv_always(!is_empty());
  3224. const RenderAttrib *attrib =
  3225. node()->get_attrib(TexGenAttrib::get_class_type());
  3226. CPT(TexGenAttrib) tga;
  3227. if (attrib != (const RenderAttrib *)NULL) {
  3228. priority = max(priority,
  3229. node()->get_state()->get_override(TextureAttrib::get_class_type()));
  3230. tga = DCAST(TexGenAttrib, attrib);
  3231. } else {
  3232. tga = DCAST(TexGenAttrib, TexGenAttrib::make());
  3233. }
  3234. node()->set_attrib(tga->add_stage(stage, mode, constant_value), priority);
  3235. }
  3236. ////////////////////////////////////////////////////////////////////
  3237. // Function: NodePath::clear_tex_gen
  3238. // Access: Published
  3239. // Description: Removes the texture coordinate generation mode from
  3240. // all texture stages on this node.
  3241. ////////////////////////////////////////////////////////////////////
  3242. void NodePath::
  3243. clear_tex_gen() {
  3244. nassertv_always(!is_empty());
  3245. node()->clear_attrib(TexGenAttrib::get_class_type());
  3246. }
  3247. ////////////////////////////////////////////////////////////////////
  3248. // Function: NodePath::clear_tex_gen
  3249. // Access: Published
  3250. // Description: Disables automatic texture coordinate generation for
  3251. // the indicated texture stage.
  3252. ////////////////////////////////////////////////////////////////////
  3253. void NodePath::
  3254. clear_tex_gen(TextureStage *stage) {
  3255. nassertv_always(!is_empty());
  3256. const RenderAttrib *attrib =
  3257. node()->get_attrib(TexGenAttrib::get_class_type());
  3258. if (attrib != (const RenderAttrib *)NULL) {
  3259. CPT(TexGenAttrib) tga = DCAST(TexGenAttrib, attrib);
  3260. tga = DCAST(TexGenAttrib, tga->remove_stage(stage));
  3261. if (tga->is_empty()) {
  3262. node()->clear_attrib(TexGenAttrib::get_class_type());
  3263. } else {
  3264. node()->set_attrib(tga);
  3265. }
  3266. }
  3267. }
  3268. ////////////////////////////////////////////////////////////////////
  3269. // Function: NodePath::has_tex_gen
  3270. // Access: Published
  3271. // Description: Returns true if there is a mode for automatic texture
  3272. // coordinate generation on the current node for the
  3273. // given stage.
  3274. ////////////////////////////////////////////////////////////////////
  3275. bool NodePath::
  3276. has_tex_gen(TextureStage *stage) const {
  3277. nassertr_always(!is_empty(), false);
  3278. const RenderAttrib *attrib =
  3279. node()->get_attrib(TexGenAttrib::get_class_type());
  3280. if (attrib != (const RenderAttrib *)NULL) {
  3281. const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
  3282. return tga->has_stage(stage);
  3283. }
  3284. return false;
  3285. }
  3286. ////////////////////////////////////////////////////////////////////
  3287. // Function: NodePath::get_tex_gen
  3288. // Access: Published
  3289. // Description: Returns the texture coordinate generation mode for
  3290. // the given stage, or M_off if there is no explicit
  3291. // mode set for the given stage.
  3292. ////////////////////////////////////////////////////////////////////
  3293. RenderAttrib::TexGenMode NodePath::
  3294. get_tex_gen(TextureStage *stage) const {
  3295. nassertr_always(!is_empty(), TexGenAttrib::M_off);
  3296. const RenderAttrib *attrib =
  3297. node()->get_attrib(TexGenAttrib::get_class_type());
  3298. if (attrib != (const RenderAttrib *)NULL) {
  3299. const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
  3300. return tga->get_mode(stage);
  3301. }
  3302. return TexGenAttrib::M_off;
  3303. }
  3304. ////////////////////////////////////////////////////////////////////
  3305. // Function: NodePath::get_tex_gen_light
  3306. // Access: Published
  3307. // Description: Returns the particular Light set for the indicated
  3308. // texgen mode's texture stage, or empty NodePath if no
  3309. // light is set. This is only meaningful if the texgen
  3310. // mode (returned by get_tex_gen()) is M_light_vector.
  3311. ////////////////////////////////////////////////////////////////////
  3312. NodePath NodePath::
  3313. get_tex_gen_light(TextureStage *stage) const {
  3314. nassertr_always(!is_empty(), NodePath::fail());
  3315. const RenderAttrib *attrib =
  3316. node()->get_attrib(TexGenAttrib::get_class_type());
  3317. if (attrib != (const RenderAttrib *)NULL) {
  3318. const TexGenAttrib *tga = DCAST(TexGenAttrib, attrib);
  3319. return tga->get_light(stage);
  3320. }
  3321. return NodePath();
  3322. }
  3323. ////////////////////////////////////////////////////////////////////
  3324. // Function: NodePath::set_tex_projector
  3325. // Access: Published
  3326. // Description: Establishes a TexProjectorEffect on this node, which
  3327. // can be used to establish projective texturing (but
  3328. // see also the NodePath::project_texture() convenience
  3329. // function), or it can be used to bind this node's
  3330. // texture transform to particular node's position in
  3331. // space, allowing a LerpInterval (for instance) to
  3332. // adjust this node's texture coordinates.
  3333. ////////////////////////////////////////////////////////////////////
  3334. void NodePath::
  3335. set_tex_projector(TextureStage *stage, const NodePath &from, const NodePath &to) {
  3336. nassertv_always(!is_empty());
  3337. const RenderEffect *effect =
  3338. node()->get_effect(TexProjectorEffect::get_class_type());
  3339. CPT(TexProjectorEffect) tpe;
  3340. if (effect != (const RenderEffect *)NULL) {
  3341. tpe = DCAST(TexProjectorEffect, effect);
  3342. } else {
  3343. tpe = DCAST(TexProjectorEffect, TexProjectorEffect::make());
  3344. }
  3345. node()->set_effect(tpe->add_stage(stage, from, to));
  3346. }
  3347. ////////////////////////////////////////////////////////////////////
  3348. // Function: NodePath::clear_tex_projector
  3349. // Access: Published
  3350. // Description: Removes the TexProjectorEffect for the indicated
  3351. // stage from this node.
  3352. ////////////////////////////////////////////////////////////////////
  3353. void NodePath::
  3354. clear_tex_projector(TextureStage *stage) {
  3355. nassertv_always(!is_empty());
  3356. const RenderEffect *effect =
  3357. node()->get_effect(TexProjectorEffect::get_class_type());
  3358. if (effect != (const RenderEffect *)NULL) {
  3359. CPT(TexProjectorEffect) tpe = DCAST(TexProjectorEffect, effect);
  3360. tpe = DCAST(TexProjectorEffect, tpe->remove_stage(stage));
  3361. if (tpe->is_empty()) {
  3362. node()->clear_effect(TexProjectorEffect::get_class_type());
  3363. } else {
  3364. node()->set_effect(tpe);
  3365. }
  3366. }
  3367. }
  3368. ////////////////////////////////////////////////////////////////////
  3369. // Function: NodePath::clear_tex_projector
  3370. // Access: Published
  3371. // Description: Removes the TexProjectorEffect for all stages from
  3372. // this node.
  3373. ////////////////////////////////////////////////////////////////////
  3374. void NodePath::
  3375. clear_tex_projector() {
  3376. nassertv_always(!is_empty());
  3377. node()->clear_effect(TexProjectorEffect::get_class_type());
  3378. }
  3379. ////////////////////////////////////////////////////////////////////
  3380. // Function: NodePath::has_tex_projector
  3381. // Access: Published
  3382. // Description: Returns true if this node has a TexProjectorEffect
  3383. // for the indicated stage, false otherwise.
  3384. ////////////////////////////////////////////////////////////////////
  3385. bool NodePath::
  3386. has_tex_projector(TextureStage *stage) const {
  3387. nassertr_always(!is_empty(), false);
  3388. const RenderEffect *effect =
  3389. node()->get_effect(TexProjectorEffect::get_class_type());
  3390. if (effect != (const RenderEffect *)NULL) {
  3391. const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
  3392. return tpe->has_stage(stage);
  3393. }
  3394. return false;
  3395. }
  3396. ////////////////////////////////////////////////////////////////////
  3397. // Function: NodePath::get_tex_projector_from
  3398. // Access: Published
  3399. // Description: Returns the "from" node associated with the
  3400. // TexProjectorEffect on the indicated stage. The
  3401. // relative transform between the "from" and the "to"
  3402. // nodes is automatically applied to the texture
  3403. // transform each frame.
  3404. ////////////////////////////////////////////////////////////////////
  3405. NodePath NodePath::
  3406. get_tex_projector_from(TextureStage *stage) const {
  3407. nassertr_always(!is_empty(), NodePath::fail());
  3408. const RenderEffect *effect =
  3409. node()->get_effect(TexProjectorEffect::get_class_type());
  3410. if (effect != (const RenderEffect *)NULL) {
  3411. const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
  3412. return tpe->get_from(stage);
  3413. }
  3414. return NodePath::not_found();
  3415. }
  3416. ////////////////////////////////////////////////////////////////////
  3417. // Function: NodePath::get_tex_projector_to
  3418. // Access: Published
  3419. // Description: Returns the "to" node associated with the
  3420. // TexProjectorEffect on the indicated stage. The
  3421. // relative transform between the "from" and the "to"
  3422. // nodes is automatically applied to the texture
  3423. // transform each frame.
  3424. ////////////////////////////////////////////////////////////////////
  3425. NodePath NodePath::
  3426. get_tex_projector_to(TextureStage *stage) const {
  3427. nassertr_always(!is_empty(), NodePath::fail());
  3428. const RenderEffect *effect =
  3429. node()->get_effect(TexProjectorEffect::get_class_type());
  3430. if (effect != (const RenderEffect *)NULL) {
  3431. const TexProjectorEffect *tpe = DCAST(TexProjectorEffect, effect);
  3432. return tpe->get_to(stage);
  3433. }
  3434. return NodePath::not_found();
  3435. }
  3436. ////////////////////////////////////////////////////////////////////
  3437. // Function: NodePath::project_texture
  3438. // Access: Published
  3439. // Description: A convenience function to enable projective texturing
  3440. // at this node level and below, using the indicated
  3441. // NodePath (which should contain a LensNode) as the
  3442. // projector.
  3443. ////////////////////////////////////////////////////////////////////
  3444. void NodePath::
  3445. project_texture(TextureStage *stage, Texture *tex, const NodePath &projector) {
  3446. nassertv(!projector.is_empty() && projector.node()->is_of_type(LensNode::get_class_type()));
  3447. set_texture(stage, tex);
  3448. set_tex_gen(stage, TexGenAttrib::M_world_position);
  3449. set_tex_projector(stage, NodePath(), projector);
  3450. }
  3451. ////////////////////////////////////////////////////////////////////
  3452. // Function: NodePath::set_normal_map
  3453. // Access: Published
  3454. // Description: A convenience function to set up a normal map on this
  3455. // geometry. This uses the single highest-priority
  3456. // light on the object only. It also requires
  3457. // multitexture, and consumes at least two texture
  3458. // stages, in addition to what may already be in use.
  3459. //
  3460. // The normal_map parameter is the texture that contains
  3461. // the normal map information (with a 3-d delta vector
  3462. // encoded into the r,g,b of each texel). texcoord_name is
  3463. // the name of the texture coordinate set that contains
  3464. // the tangent and binormal we wish to use. If
  3465. // preserve_color is true, then one additional texture
  3466. // stage is consumed to blend in the geometry's original
  3467. // vertex color.
  3468. //
  3469. // Only one normal map may be in effect through this
  3470. // interface at any given time.
  3471. ////////////////////////////////////////////////////////////////////
  3472. void NodePath::
  3473. set_normal_map(Texture *normal_map, const string &texcoord_name,
  3474. bool preserve_color) {
  3475. clear_normal_map();
  3476. // First, we apply the normal map itself, to the bottom layer.
  3477. PT(TextureStage) normal_map_ts = new TextureStage("__normal_map");
  3478. normal_map_ts->set_texcoord_name(texcoord_name);
  3479. normal_map_ts->set_sort(-20);
  3480. normal_map_ts->set_mode(TextureStage::M_replace);
  3481. set_texture(normal_map_ts, normal_map);
  3482. // Then, we apply a normalization map, to normalize, per-pixel, the
  3483. // vector to the light.
  3484. PT(Texture) normalization_map = TexturePool::get_normalization_cube_map(32);
  3485. PT(TextureStage) normalization_map_ts = new TextureStage("__normalization_map");
  3486. normalization_map_ts->set_combine_rgb
  3487. (TextureStage::CM_dot3_rgb,
  3488. TextureStage::CS_texture, TextureStage::CO_src_color,
  3489. TextureStage::CS_previous, TextureStage::CO_src_color);
  3490. normalization_map_ts->set_texcoord_name("light_vector");
  3491. normalization_map_ts->set_sort(-15);
  3492. set_texture(normalization_map_ts, normalization_map);
  3493. // Finally, we enable M_light_vector texture coordinate generation.
  3494. set_tex_gen(normalization_map_ts, TexGenAttrib::M_light_vector,
  3495. texcoord_name, NodePath());
  3496. if (preserve_color) {
  3497. // One more stage to get back the original color.
  3498. PT(TextureStage) orig_color_ts = new TextureStage("__orig_color");
  3499. orig_color_ts->set_combine_rgb
  3500. (TextureStage::CM_modulate,
  3501. TextureStage::CS_primary_color, TextureStage::CO_src_color,
  3502. TextureStage::CS_previous, TextureStage::CO_src_color);
  3503. set_texture(orig_color_ts, normal_map);
  3504. }
  3505. }
  3506. ////////////////////////////////////////////////////////////////////
  3507. // Function: NodePath::clear_normal_map
  3508. // Access: Published
  3509. // Description: Undoes the effect of a previous call to
  3510. // set_normal_map().
  3511. ////////////////////////////////////////////////////////////////////
  3512. void NodePath::
  3513. clear_normal_map() {
  3514. // Scan through the TextureStages, and if we find any whose name
  3515. // matches one of the stages that would have been left by
  3516. // set_normal_map(), remove it from the state.
  3517. CPT(RenderAttrib) attrib =
  3518. get_state()->get_attrib(TextureAttrib::get_class_type());
  3519. if (attrib != (const RenderAttrib *)NULL) {
  3520. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  3521. for (int i = 0; i < ta->get_num_on_stages(); i++) {
  3522. TextureStage *stage = ta->get_on_stage(i);
  3523. if (stage->get_name() == "__normal_map") {
  3524. clear_texture(stage);
  3525. } else if (stage->get_name() == "__normalization_map") {
  3526. clear_texture(stage);
  3527. clear_tex_gen(stage);
  3528. } else if (stage->get_name() == "__orig_color") {
  3529. clear_texture(stage);
  3530. }
  3531. }
  3532. }
  3533. }
  3534. ////////////////////////////////////////////////////////////////////
  3535. // Function: NodePath::has_vertex_column
  3536. // Access: Published
  3537. // Description: Returns true if there are at least some vertices at
  3538. // this node and below that contain a reference to the
  3539. // indicated vertex data column name, false otherwise.
  3540. //
  3541. // This is particularly useful for testing whether a
  3542. // particular model has a given texture coordinate set
  3543. // (but see has_texcoord()).
  3544. ////////////////////////////////////////////////////////////////////
  3545. bool NodePath::
  3546. has_vertex_column(const InternalName *name) const {
  3547. nassertr_always(!is_empty(), false);
  3548. return r_has_vertex_column(node(), name);
  3549. }
  3550. ////////////////////////////////////////////////////////////////////
  3551. // Function: NodePath::find_all_vertex_columns
  3552. // Access: Published
  3553. // Description: Returns a list of all vertex array columns stored on
  3554. // some geometry found at this node level and below.
  3555. ////////////////////////////////////////////////////////////////////
  3556. InternalNameCollection NodePath::
  3557. find_all_vertex_columns() const {
  3558. nassertr_always(!is_empty(), InternalNameCollection());
  3559. InternalNames vertex_columns;
  3560. r_find_all_vertex_columns(node(), vertex_columns);
  3561. InternalNameCollection tc;
  3562. InternalNames::iterator ti;
  3563. for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
  3564. tc.add_name(*ti);
  3565. }
  3566. return tc;
  3567. }
  3568. ////////////////////////////////////////////////////////////////////
  3569. // Function: NodePath::find_all_vertex_columns
  3570. // Access: Published
  3571. // Description: Returns a list of all vertex array columns stored on
  3572. // some geometry found at this node level and below that
  3573. // match the indicated name (which may contain wildcard
  3574. // characters).
  3575. ////////////////////////////////////////////////////////////////////
  3576. InternalNameCollection NodePath::
  3577. find_all_vertex_columns(const string &name) const {
  3578. nassertr_always(!is_empty(), InternalNameCollection());
  3579. InternalNames vertex_columns;
  3580. r_find_all_vertex_columns(node(), vertex_columns);
  3581. GlobPattern glob(name);
  3582. InternalNameCollection tc;
  3583. InternalNames::iterator ti;
  3584. for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
  3585. InternalName *name = (*ti);
  3586. if (glob.matches(name->get_name())) {
  3587. tc.add_name(name);
  3588. }
  3589. }
  3590. return tc;
  3591. }
  3592. ////////////////////////////////////////////////////////////////////
  3593. // Function: NodePath::find_all_texcoords
  3594. // Access: Published
  3595. // Description: Returns a list of all texture coordinate sets used by
  3596. // any geometry at this node level and below.
  3597. ////////////////////////////////////////////////////////////////////
  3598. InternalNameCollection NodePath::
  3599. find_all_texcoords() const {
  3600. nassertr_always(!is_empty(), InternalNameCollection());
  3601. InternalNames vertex_columns;
  3602. r_find_all_vertex_columns(node(), vertex_columns);
  3603. CPT(InternalName) texcoord_name = InternalName::get_texcoord();
  3604. InternalNameCollection tc;
  3605. InternalNames::iterator ti;
  3606. for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
  3607. if ((*ti)->get_top() == texcoord_name) {
  3608. tc.add_name(*ti);
  3609. }
  3610. }
  3611. return tc;
  3612. }
  3613. ////////////////////////////////////////////////////////////////////
  3614. // Function: NodePath::find_all_texcoords
  3615. // Access: Published
  3616. // Description: Returns a list of all texture coordinate sets used by
  3617. // any geometry at this node level and below that match
  3618. // the indicated name (which may contain wildcard
  3619. // characters).
  3620. ////////////////////////////////////////////////////////////////////
  3621. InternalNameCollection NodePath::
  3622. find_all_texcoords(const string &name) const {
  3623. nassertr_always(!is_empty(), InternalNameCollection());
  3624. InternalNames vertex_columns;
  3625. r_find_all_vertex_columns(node(), vertex_columns);
  3626. GlobPattern glob(name);
  3627. CPT(InternalName) texcoord_name = InternalName::get_texcoord();
  3628. InternalNameCollection tc;
  3629. InternalNames::iterator ti;
  3630. for (ti = vertex_columns.begin(); ti != vertex_columns.end(); ++ti) {
  3631. InternalName *name = (*ti);
  3632. if (name->get_top() == texcoord_name) {
  3633. // This is a texture coordinate name. Figure out the basename
  3634. // of the texture coordinates.
  3635. int index = name->find_ancestor("texcoord");
  3636. nassertr(index != -1, InternalNameCollection());
  3637. string net_basename = name->get_net_basename(index - 1);
  3638. if (glob.matches(net_basename)) {
  3639. tc.add_name(name);
  3640. }
  3641. }
  3642. }
  3643. return tc;
  3644. }
  3645. ////////////////////////////////////////////////////////////////////
  3646. // Function: NodePath::find_texture
  3647. // Access: Published
  3648. // Description: Returns the first texture found applied to geometry
  3649. // at this node or below that matches the indicated name
  3650. // (which may contain wildcards). Returns the texture
  3651. // if it is found, or NULL if it is not.
  3652. ////////////////////////////////////////////////////////////////////
  3653. Texture *NodePath::
  3654. find_texture(const string &name) const {
  3655. nassertr_always(!is_empty(), NULL);
  3656. GlobPattern glob(name);
  3657. return r_find_texture(node(), get_net_state(), glob);
  3658. }
  3659. ////////////////////////////////////////////////////////////////////
  3660. // Function: NodePath::find_texture
  3661. // Access: Published
  3662. // Description: Returns the first texture found applied to geometry
  3663. // at this node or below that is assigned to the
  3664. // indicated texture stage. Returns the texture if it
  3665. // is found, or NULL if it is not.
  3666. ////////////////////////////////////////////////////////////////////
  3667. Texture *NodePath::
  3668. find_texture(TextureStage *stage) const {
  3669. nassertr_always(!is_empty(), NULL);
  3670. return r_find_texture(node(), stage);
  3671. }
  3672. ////////////////////////////////////////////////////////////////////
  3673. // Function: NodePath::find_all_textures
  3674. // Access: Published
  3675. // Description: Returns a list of a textures applied to geometry at
  3676. // this node and below.
  3677. ////////////////////////////////////////////////////////////////////
  3678. TextureCollection NodePath::
  3679. find_all_textures() const {
  3680. nassertr_always(!is_empty(), TextureCollection());
  3681. Textures textures;
  3682. r_find_all_textures(node(), get_net_state(), textures);
  3683. TextureCollection tc;
  3684. Textures::iterator ti;
  3685. for (ti = textures.begin(); ti != textures.end(); ++ti) {
  3686. tc.add_texture(*ti);
  3687. }
  3688. return tc;
  3689. }
  3690. ////////////////////////////////////////////////////////////////////
  3691. // Function: NodePath::find_all_textures
  3692. // Access: Published
  3693. // Description: Returns a list of a textures applied to geometry at
  3694. // this node and below that match the indicated name
  3695. // (which may contain wildcard characters).
  3696. ////////////////////////////////////////////////////////////////////
  3697. TextureCollection NodePath::
  3698. find_all_textures(const string &name) const {
  3699. nassertr_always(!is_empty(), TextureCollection());
  3700. Textures textures;
  3701. r_find_all_textures(node(), get_net_state(), textures);
  3702. GlobPattern glob(name);
  3703. TextureCollection tc;
  3704. Textures::iterator ti;
  3705. for (ti = textures.begin(); ti != textures.end(); ++ti) {
  3706. Texture *texture = (*ti);
  3707. if (glob.matches(texture->get_name())) {
  3708. tc.add_texture(texture);
  3709. }
  3710. }
  3711. return tc;
  3712. }
  3713. ////////////////////////////////////////////////////////////////////
  3714. // Function: NodePath::find_all_textures
  3715. // Access: Published
  3716. // Description: Returns a list of a textures on geometry at
  3717. // this node and below that are assigned to the
  3718. // indicated texture stage.
  3719. ////////////////////////////////////////////////////////////////////
  3720. TextureCollection NodePath::
  3721. find_all_textures(TextureStage *stage) const {
  3722. nassertr_always(!is_empty(), TextureCollection());
  3723. Textures textures;
  3724. r_find_all_textures(node(), stage, textures);
  3725. TextureCollection tc;
  3726. Textures::iterator ti;
  3727. for (ti = textures.begin(); ti != textures.end(); ++ti) {
  3728. Texture *texture = (*ti);
  3729. tc.add_texture(texture);
  3730. }
  3731. return tc;
  3732. }
  3733. ////////////////////////////////////////////////////////////////////
  3734. // Function: NodePath::find_texture_stage
  3735. // Access: Published
  3736. // Description: Returns the first TextureStage found applied to
  3737. // geometry at this node or below that matches the
  3738. // indicated name (which may contain wildcards).
  3739. // Returns the TextureStage if it is found, or NULL if
  3740. // it is not.
  3741. ////////////////////////////////////////////////////////////////////
  3742. TextureStage *NodePath::
  3743. find_texture_stage(const string &name) const {
  3744. nassertr_always(!is_empty(), NULL);
  3745. GlobPattern glob(name);
  3746. return r_find_texture_stage(node(), get_net_state(), glob);
  3747. }
  3748. ////////////////////////////////////////////////////////////////////
  3749. // Function: NodePath::find_all_texture_stages
  3750. // Access: Published
  3751. // Description: Returns a list of a TextureStages applied to geometry
  3752. // at this node and below.
  3753. ////////////////////////////////////////////////////////////////////
  3754. TextureStageCollection NodePath::
  3755. find_all_texture_stages() const {
  3756. nassertr_always(!is_empty(), TextureStageCollection());
  3757. TextureStages texture_stages;
  3758. r_find_all_texture_stages(node(), get_net_state(), texture_stages);
  3759. TextureStageCollection tc;
  3760. TextureStages::iterator ti;
  3761. for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
  3762. tc.add_texture_stage(*ti);
  3763. }
  3764. return tc;
  3765. }
  3766. ////////////////////////////////////////////////////////////////////
  3767. // Function: NodePath::unify_texture_stages
  3768. // Access: Published
  3769. // Description: Searches through all TextureStages at this node and
  3770. // below. Any TextureStages that share the same name as
  3771. // the indicated TextureStage object are replaced with
  3772. // this object, thus ensuring that all geometry at this
  3773. // node and below with a particular TextureStage name is
  3774. // using the same TextureStage object.
  3775. ////////////////////////////////////////////////////////////////////
  3776. void NodePath::
  3777. unify_texture_stages(TextureStage *stage) {
  3778. nassertv_always(!is_empty());
  3779. r_unify_texture_stages(node(), stage);
  3780. }
  3781. ////////////////////////////////////////////////////////////////////
  3782. // Function: NodePath::find_all_texture_stages
  3783. // Access: Published
  3784. // Description: Returns a list of a TextureStages applied to geometry
  3785. // at this node and below that match the indicated name
  3786. // (which may contain wildcard characters).
  3787. ////////////////////////////////////////////////////////////////////
  3788. TextureStageCollection NodePath::
  3789. find_all_texture_stages(const string &name) const {
  3790. nassertr_always(!is_empty(), TextureStageCollection());
  3791. TextureStages texture_stages;
  3792. r_find_all_texture_stages(node(), get_net_state(), texture_stages);
  3793. GlobPattern glob(name);
  3794. TextureStageCollection tc;
  3795. TextureStages::iterator ti;
  3796. for (ti = texture_stages.begin(); ti != texture_stages.end(); ++ti) {
  3797. TextureStage *texture_stage = (*ti);
  3798. if (glob.matches(texture_stage->get_name())) {
  3799. tc.add_texture_stage(texture_stage);
  3800. }
  3801. }
  3802. return tc;
  3803. }
  3804. ////////////////////////////////////////////////////////////////////
  3805. // Function: NodePath::find_material
  3806. // Access: Published
  3807. // Description: Returns the first material found applied to geometry
  3808. // at this node or below that matches the indicated name
  3809. // (which may contain wildcards). Returns the material
  3810. // if it is found, or NULL if it is not.
  3811. ////////////////////////////////////////////////////////////////////
  3812. Material *NodePath::
  3813. find_material(const string &name) const {
  3814. nassertr_always(!is_empty(), NULL);
  3815. GlobPattern glob(name);
  3816. return r_find_material(node(), get_net_state(), glob);
  3817. }
  3818. ////////////////////////////////////////////////////////////////////
  3819. // Function: NodePath::find_all_materials
  3820. // Access: Published
  3821. // Description: Returns a list of a materials applied to geometry at
  3822. // this node and below.
  3823. ////////////////////////////////////////////////////////////////////
  3824. MaterialCollection NodePath::
  3825. find_all_materials() const {
  3826. nassertr_always(!is_empty(), MaterialCollection());
  3827. Materials materials;
  3828. r_find_all_materials(node(), get_net_state(), materials);
  3829. MaterialCollection tc;
  3830. Materials::iterator ti;
  3831. for (ti = materials.begin(); ti != materials.end(); ++ti) {
  3832. tc.add_material(*ti);
  3833. }
  3834. return tc;
  3835. }
  3836. ////////////////////////////////////////////////////////////////////
  3837. // Function: NodePath::find_all_materials
  3838. // Access: Published
  3839. // Description: Returns a list of a materials applied to geometry at
  3840. // this node and below that match the indicated name
  3841. // (which may contain wildcard characters).
  3842. ////////////////////////////////////////////////////////////////////
  3843. MaterialCollection NodePath::
  3844. find_all_materials(const string &name) const {
  3845. nassertr_always(!is_empty(), MaterialCollection());
  3846. Materials materials;
  3847. r_find_all_materials(node(), get_net_state(), materials);
  3848. GlobPattern glob(name);
  3849. MaterialCollection tc;
  3850. Materials::iterator ti;
  3851. for (ti = materials.begin(); ti != materials.end(); ++ti) {
  3852. Material *material = (*ti);
  3853. if (glob.matches(material->get_name())) {
  3854. tc.add_material(material);
  3855. }
  3856. }
  3857. return tc;
  3858. }
  3859. ////////////////////////////////////////////////////////////////////
  3860. // Function: NodePath::set_material
  3861. // Access: Published
  3862. // Description: Sets the geometry at this level and below to render
  3863. // using the indicated material.
  3864. //
  3865. // Previously, this operation made a copy of the
  3866. // material structure, but nowadays it assigns the
  3867. // pointer directly.
  3868. ////////////////////////////////////////////////////////////////////
  3869. void NodePath::
  3870. set_material(Material *mat, int priority) {
  3871. nassertv_always(!is_empty());
  3872. nassertv(mat != NULL);
  3873. node()->set_attrib(MaterialAttrib::make(mat), priority);
  3874. }
  3875. ////////////////////////////////////////////////////////////////////
  3876. // Function: NodePath::set_material_off
  3877. // Access: Published
  3878. // Description: Sets the geometry at this level and below to render
  3879. // using no material. This is normally the default, but
  3880. // it may be useful to use this to contradict
  3881. // set_material() at a higher node level (or, with a
  3882. // priority, to override a set_material() at a lower
  3883. // level).
  3884. ////////////////////////////////////////////////////////////////////
  3885. void NodePath::
  3886. set_material_off(int priority) {
  3887. nassertv_always(!is_empty());
  3888. node()->set_attrib(MaterialAttrib::make_off(), priority);
  3889. }
  3890. ////////////////////////////////////////////////////////////////////
  3891. // Function: NodePath::clear_material
  3892. // Access: Published
  3893. // Description: Completely removes any material adjustment that may
  3894. // have been set via set_material() from this particular
  3895. // node.
  3896. ////////////////////////////////////////////////////////////////////
  3897. void NodePath::
  3898. clear_material() {
  3899. nassertv_always(!is_empty());
  3900. node()->clear_attrib(MaterialAttrib::get_class_type());
  3901. }
  3902. ////////////////////////////////////////////////////////////////////
  3903. // Function: NodePath::has_material
  3904. // Access: Published
  3905. // Description: Returns true if a material has been applied to this
  3906. // particular node via set_material(), false otherwise.
  3907. ////////////////////////////////////////////////////////////////////
  3908. bool NodePath::
  3909. has_material() const {
  3910. nassertr_always(!is_empty(), false);
  3911. const RenderAttrib *attrib =
  3912. node()->get_attrib(MaterialAttrib::get_class_type());
  3913. if (attrib != (const RenderAttrib *)NULL) {
  3914. const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
  3915. return !ma->is_off();
  3916. }
  3917. return false;
  3918. }
  3919. ////////////////////////////////////////////////////////////////////
  3920. // Function: NodePath::get_material
  3921. // Access: Published
  3922. // Description: Returns the material that has been set on this
  3923. // particular node, or NULL if no material has been set.
  3924. // This is not necessarily the material that will be
  3925. // applied to the geometry at or below this level, as
  3926. // another material at a higher or lower level may
  3927. // override.
  3928. // See also find_material().
  3929. ////////////////////////////////////////////////////////////////////
  3930. PT(Material) NodePath::
  3931. get_material() const {
  3932. nassertr_always(!is_empty(), NULL);
  3933. const RenderAttrib *attrib =
  3934. node()->get_attrib(MaterialAttrib::get_class_type());
  3935. if (attrib != (const RenderAttrib *)NULL) {
  3936. const MaterialAttrib *ma = DCAST(MaterialAttrib, attrib);
  3937. return ma->get_material();
  3938. }
  3939. return NULL;
  3940. }
  3941. ////////////////////////////////////////////////////////////////////
  3942. // Function: NodePath::set_fog
  3943. // Access: Published
  3944. // Description: Sets the geometry at this level and below to render
  3945. // using the indicated fog.
  3946. ////////////////////////////////////////////////////////////////////
  3947. void NodePath::
  3948. set_fog(Fog *fog, int priority) {
  3949. nassertv_always(!is_empty());
  3950. node()->set_attrib(FogAttrib::make(fog), priority);
  3951. }
  3952. ////////////////////////////////////////////////////////////////////
  3953. // Function: NodePath::set_fog_off
  3954. // Access: Published
  3955. // Description: Sets the geometry at this level and below to render
  3956. // using no fog. This is normally the default, but
  3957. // it may be useful to use this to contradict
  3958. // set_fog() at a higher node level (or, with a
  3959. // priority, to override a set_fog() at a lower
  3960. // level).
  3961. ////////////////////////////////////////////////////////////////////
  3962. void NodePath::
  3963. set_fog_off(int priority) {
  3964. nassertv_always(!is_empty());
  3965. node()->set_attrib(FogAttrib::make_off(), priority);
  3966. }
  3967. ////////////////////////////////////////////////////////////////////
  3968. // Function: NodePath::clear_fog
  3969. // Access: Published
  3970. // Description: Completely removes any fog adjustment that may
  3971. // have been set via set_fog() or set_fog_off()
  3972. // from this particular node. This allows whatever
  3973. // fogs might be otherwise affecting the geometry to
  3974. // show instead.
  3975. ////////////////////////////////////////////////////////////////////
  3976. void NodePath::
  3977. clear_fog() {
  3978. nassertv_always(!is_empty());
  3979. node()->clear_attrib(FogAttrib::get_class_type());
  3980. }
  3981. ////////////////////////////////////////////////////////////////////
  3982. // Function: NodePath::has_fog
  3983. // Access: Published
  3984. // Description: Returns true if a fog has been applied to this
  3985. // particular node via set_fog(), false otherwise.
  3986. // This is not the same thing as asking whether the
  3987. // geometry at this node will be rendered with
  3988. // fog, as there may be a fog in effect from a higher or
  3989. // lower level.
  3990. ////////////////////////////////////////////////////////////////////
  3991. bool NodePath::
  3992. has_fog() const {
  3993. nassertr_always(!is_empty(), false);
  3994. const RenderAttrib *attrib =
  3995. node()->get_attrib(FogAttrib::get_class_type());
  3996. if (attrib != (const RenderAttrib *)NULL) {
  3997. const FogAttrib *fa = DCAST(FogAttrib, attrib);
  3998. return !fa->is_off();
  3999. }
  4000. return false;
  4001. }
  4002. ////////////////////////////////////////////////////////////////////
  4003. // Function: NodePath::has_fog_off
  4004. // Access: Published
  4005. // Description: Returns true if a fog has been specifically
  4006. // disabled on this particular node via
  4007. // set_fog_off(), false otherwise. This is not the
  4008. // same thing as asking whether the geometry at this
  4009. // node will be rendered unfogged, as there may be a
  4010. // fog in effect from a higher or lower level.
  4011. ////////////////////////////////////////////////////////////////////
  4012. bool NodePath::
  4013. has_fog_off() const {
  4014. nassertr_always(!is_empty(), false);
  4015. const RenderAttrib *attrib =
  4016. node()->get_attrib(FogAttrib::get_class_type());
  4017. if (attrib != (const RenderAttrib *)NULL) {
  4018. const FogAttrib *fa = DCAST(FogAttrib, attrib);
  4019. return fa->is_off();
  4020. }
  4021. return false;
  4022. }
  4023. ////////////////////////////////////////////////////////////////////
  4024. // Function: NodePath::get_fog
  4025. // Access: Published
  4026. // Description: Returns the fog that has been set on this
  4027. // particular node, or NULL if no fog has been set.
  4028. // This is not necessarily the fog that will be
  4029. // applied to the geometry at or below this level, as
  4030. // another fog at a higher or lower level may
  4031. // override.
  4032. ////////////////////////////////////////////////////////////////////
  4033. Fog *NodePath::
  4034. get_fog() const {
  4035. nassertr_always(!is_empty(), NULL);
  4036. const RenderAttrib *attrib =
  4037. node()->get_attrib(FogAttrib::get_class_type());
  4038. if (attrib != (const RenderAttrib *)NULL) {
  4039. const FogAttrib *fa = DCAST(FogAttrib, attrib);
  4040. return fa->get_fog();
  4041. }
  4042. return NULL;
  4043. }
  4044. ////////////////////////////////////////////////////////////////////
  4045. // Function: NodePath::set_render_mode_wireframe
  4046. // Access: Published
  4047. // Description: Sets up the geometry at this level and below (unless
  4048. // overridden) to render in wireframe mode.
  4049. ////////////////////////////////////////////////////////////////////
  4050. void NodePath::
  4051. set_render_mode_wireframe(int priority) {
  4052. nassertv_always(!is_empty());
  4053. float thickness = get_render_mode_thickness();
  4054. bool perspective = get_render_mode_perspective();
  4055. node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_wireframe, thickness, perspective), priority);
  4056. }
  4057. ////////////////////////////////////////////////////////////////////
  4058. // Function: NodePath::set_render_mode_filled
  4059. // Access: Published
  4060. // Description: Sets up the geometry at this level and below (unless
  4061. // overridden) to render in filled (i.e. not wireframe)
  4062. // mode.
  4063. ////////////////////////////////////////////////////////////////////
  4064. void NodePath::
  4065. set_render_mode_filled(int priority) {
  4066. nassertv_always(!is_empty());
  4067. float thickness = get_render_mode_thickness();
  4068. bool perspective = get_render_mode_perspective();
  4069. node()->set_attrib(RenderModeAttrib::make(RenderModeAttrib::M_filled, thickness, perspective), priority);
  4070. }
  4071. ////////////////////////////////////////////////////////////////////
  4072. // Function: NodePath::set_render_mode_perspective
  4073. // Access: Published
  4074. // Description: Sets up the point geometry at this level and below to
  4075. // render as perspective sprites (that is, billboarded
  4076. // quads). The thickness, as specified with
  4077. // set_render_mode_thickness(), is the width of each
  4078. // point in 3-D units, unless it is overridden on a
  4079. // per-vertex basis. This does not affect geometry
  4080. // other than points.
  4081. //
  4082. // If you want the quads to be individually textured,
  4083. // you should also set a TexGenAttrib::M_point_sprite on
  4084. // the node.
  4085. ////////////////////////////////////////////////////////////////////
  4086. void NodePath::
  4087. set_render_mode_perspective(bool perspective, int priority) {
  4088. nassertv_always(!is_empty());
  4089. RenderModeAttrib::Mode mode = get_render_mode();
  4090. float thickness = get_render_mode_thickness();
  4091. node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority);
  4092. }
  4093. ////////////////////////////////////////////////////////////////////
  4094. // Function: NodePath::set_render_mode_thickness
  4095. // Access: Published
  4096. // Description: Sets up the point geometry at this level and below to
  4097. // render as thick points (that is, billboarded
  4098. // quads). The thickness is in pixels, unless
  4099. // set_render_mode_perspective is also true, in which
  4100. // case it is in 3-D units.
  4101. //
  4102. // If you want the quads to be individually textured,
  4103. // you should also set a TexGenAttrib::M_point_sprite on
  4104. // the node.
  4105. ////////////////////////////////////////////////////////////////////
  4106. void NodePath::
  4107. set_render_mode_thickness(float thickness, int priority) {
  4108. nassertv_always(!is_empty());
  4109. RenderModeAttrib::Mode mode = get_render_mode();
  4110. bool perspective = get_render_mode_perspective();
  4111. node()->set_attrib(RenderModeAttrib::make(mode, thickness, perspective), priority);
  4112. }
  4113. ////////////////////////////////////////////////////////////////////
  4114. // Function: NodePath::set_render_mode
  4115. // Access: Published
  4116. // Description: Sets up the geometry at this level and below (unless
  4117. // overridden) to render in the specified mode and with
  4118. // the indicated line and/or point thickness.
  4119. ////////////////////////////////////////////////////////////////////
  4120. void NodePath::
  4121. set_render_mode(RenderModeAttrib::Mode mode, float thickness, int priority) {
  4122. nassertv_always(!is_empty());
  4123. node()->set_attrib(RenderModeAttrib::make(mode, thickness), priority);
  4124. }
  4125. ////////////////////////////////////////////////////////////////////
  4126. // Function: NodePath::clear_render_mode
  4127. // Access: Published
  4128. // Description: Completely removes any render mode adjustment that
  4129. // may have been set on this node via
  4130. // set_render_mode_wireframe() or
  4131. // set_render_mode_filled().
  4132. ////////////////////////////////////////////////////////////////////
  4133. void NodePath::
  4134. clear_render_mode() {
  4135. nassertv_always(!is_empty());
  4136. node()->clear_attrib(RenderModeAttrib::get_class_type());
  4137. }
  4138. ////////////////////////////////////////////////////////////////////
  4139. // Function: NodePath::has_render_mode
  4140. // Access: Published
  4141. // Description: Returns true if a render mode has been explicitly set
  4142. // on this particular node via set_render_mode() (or
  4143. // set_render_mode_wireframe() or
  4144. // set_render_mode_filled()), false otherwise.
  4145. ////////////////////////////////////////////////////////////////////
  4146. bool NodePath::
  4147. has_render_mode() const {
  4148. nassertr_always(!is_empty(), false);
  4149. return node()->has_attrib(RenderModeAttrib::get_class_type());
  4150. }
  4151. ////////////////////////////////////////////////////////////////////
  4152. // Function: NodePath::get_render_mode
  4153. // Access: Published
  4154. // Description: Returns the render mode that has been specifically
  4155. // set on this node via set_render_mode(), or
  4156. // M_unchanged if nothing has been set.
  4157. ////////////////////////////////////////////////////////////////////
  4158. RenderModeAttrib::Mode NodePath::
  4159. get_render_mode() const {
  4160. nassertr_always(!is_empty(), RenderModeAttrib::M_unchanged);
  4161. const RenderAttrib *attrib =
  4162. node()->get_attrib(RenderModeAttrib::get_class_type());
  4163. if (attrib != (const RenderAttrib *)NULL) {
  4164. const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
  4165. return ta->get_mode();
  4166. }
  4167. return RenderModeAttrib::M_unchanged;
  4168. }
  4169. ////////////////////////////////////////////////////////////////////
  4170. // Function: NodePath::get_render_mode_thickness
  4171. // Access: Published
  4172. // Description: Returns the render mode thickness that has been
  4173. // specifically set on this node via set_render_mode(),
  4174. // or 1.0 if nothing has been set.
  4175. ////////////////////////////////////////////////////////////////////
  4176. float NodePath::
  4177. get_render_mode_thickness() const {
  4178. nassertr_always(!is_empty(), 0.0f);
  4179. const RenderAttrib *attrib =
  4180. node()->get_attrib(RenderModeAttrib::get_class_type());
  4181. if (attrib != (const RenderAttrib *)NULL) {
  4182. const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
  4183. return ta->get_thickness();
  4184. }
  4185. return 1.0f;
  4186. }
  4187. ////////////////////////////////////////////////////////////////////
  4188. // Function: NodePath::get_render_mode_perspective
  4189. // Access: Published
  4190. // Description: Returns the flag that has been set on this node via
  4191. // set_render_mode_perspective(), or false if no flag
  4192. // has been set.
  4193. ////////////////////////////////////////////////////////////////////
  4194. bool NodePath::
  4195. get_render_mode_perspective() const {
  4196. nassertr_always(!is_empty(), 0.0f);
  4197. const RenderAttrib *attrib =
  4198. node()->get_attrib(RenderModeAttrib::get_class_type());
  4199. if (attrib != (const RenderAttrib *)NULL) {
  4200. const RenderModeAttrib *ta = DCAST(RenderModeAttrib, attrib);
  4201. return ta->get_perspective();
  4202. }
  4203. return false;
  4204. }
  4205. ////////////////////////////////////////////////////////////////////
  4206. // Function: NodePath::set_two_sided
  4207. // Access: Published
  4208. // Description: Specifically sets or disables two-sided rendering
  4209. // mode on this particular node. If no other nodes
  4210. // override, this will cause backfacing polygons to be
  4211. // drawn (in two-sided mode, true) or culled (in
  4212. // one-sided mode, false).
  4213. ////////////////////////////////////////////////////////////////////
  4214. void NodePath::
  4215. set_two_sided(bool two_sided, int priority) {
  4216. nassertv_always(!is_empty());
  4217. CullFaceAttrib::Mode mode =
  4218. two_sided ?
  4219. CullFaceAttrib::M_cull_none :
  4220. CullFaceAttrib::M_cull_clockwise;
  4221. node()->set_attrib(CullFaceAttrib::make(mode), priority);
  4222. }
  4223. ////////////////////////////////////////////////////////////////////
  4224. // Function: NodePath::clear_two_sided
  4225. // Access: Published
  4226. // Description: Completely removes any two-sided adjustment that
  4227. // may have been set on this node via set_two_sided().
  4228. // The geometry at this level and below will
  4229. // subsequently be rendered either two-sided or
  4230. // one-sided, according to whatever other nodes may have
  4231. // had set_two_sided() on it, or according to the
  4232. // initial state otherwise.
  4233. ////////////////////////////////////////////////////////////////////
  4234. void NodePath::
  4235. clear_two_sided() {
  4236. nassertv_always(!is_empty());
  4237. node()->clear_attrib(CullFaceAttrib::get_class_type());
  4238. }
  4239. ////////////////////////////////////////////////////////////////////
  4240. // Function: NodePath::has_two_sided
  4241. // Access: Published
  4242. // Description: Returns true if a two-sided adjustment has been
  4243. // explicitly set on this particular node via
  4244. // set_two_sided(). If this returns true, then
  4245. // get_two_sided() may be called to determine which has
  4246. // been set.
  4247. ////////////////////////////////////////////////////////////////////
  4248. bool NodePath::
  4249. has_two_sided() const {
  4250. nassertr_always(!is_empty(), false);
  4251. return node()->has_attrib(CullFaceAttrib::get_class_type());
  4252. }
  4253. ////////////////////////////////////////////////////////////////////
  4254. // Function: NodePath::get_two_sided
  4255. // Access: Published
  4256. // Description: Returns true if two-sided rendering has been
  4257. // specifically set on this node via set_two_sided(), or
  4258. // false if one-sided rendering has been specifically
  4259. // set, or if nothing has been specifically set. See
  4260. // also has_two_sided(). This does not necessarily
  4261. // imply that the geometry will or will not be rendered
  4262. // two-sided, as there may be other nodes that override.
  4263. ////////////////////////////////////////////////////////////////////
  4264. bool NodePath::
  4265. get_two_sided() const {
  4266. nassertr_always(!is_empty(), false);
  4267. const RenderAttrib *attrib =
  4268. node()->get_attrib(CullFaceAttrib::get_class_type());
  4269. if (attrib != (const RenderAttrib *)NULL) {
  4270. const CullFaceAttrib *cfa = DCAST(CullFaceAttrib, attrib);
  4271. return (cfa->get_actual_mode() == CullFaceAttrib::M_cull_none);
  4272. }
  4273. return false;
  4274. }
  4275. ////////////////////////////////////////////////////////////////////
  4276. // Function: NodePath::set_depth_test
  4277. // Access: Published
  4278. // Description: Specifically sets or disables the testing of the
  4279. // depth buffer on this particular node. This is
  4280. // normally on in the 3-d scene graph and off in the 2-d
  4281. // scene graph; it should be on for rendering most 3-d
  4282. // objects properly.
  4283. ////////////////////////////////////////////////////////////////////
  4284. void NodePath::
  4285. set_depth_test(bool depth_test, int priority) {
  4286. nassertv_always(!is_empty());
  4287. DepthTestAttrib::PandaCompareFunc mode =
  4288. depth_test ?
  4289. DepthTestAttrib::M_less :
  4290. DepthTestAttrib::M_none;
  4291. node()->set_attrib(DepthTestAttrib::make(mode), priority);
  4292. }
  4293. ////////////////////////////////////////////////////////////////////
  4294. // Function: NodePath::clear_depth_test
  4295. // Access: Published
  4296. // Description: Completely removes any depth-test adjustment that
  4297. // may have been set on this node via set_depth_test().
  4298. ////////////////////////////////////////////////////////////////////
  4299. void NodePath::
  4300. clear_depth_test() {
  4301. nassertv_always(!is_empty());
  4302. node()->clear_attrib(DepthTestAttrib::get_class_type());
  4303. }
  4304. ////////////////////////////////////////////////////////////////////
  4305. // Function: NodePath::has_depth_test
  4306. // Access: Published
  4307. // Description: Returns true if a depth-test adjustment has been
  4308. // explicitly set on this particular node via
  4309. // set_depth_test(). If this returns true, then
  4310. // get_depth_test() may be called to determine which has
  4311. // been set.
  4312. ////////////////////////////////////////////////////////////////////
  4313. bool NodePath::
  4314. has_depth_test() const {
  4315. nassertr_always(!is_empty(), false);
  4316. return node()->has_attrib(DepthTestAttrib::get_class_type());
  4317. }
  4318. ////////////////////////////////////////////////////////////////////
  4319. // Function: NodePath::get_depth_test
  4320. // Access: Published
  4321. // Description: Returns true if depth-test rendering has been
  4322. // specifically set on this node via set_depth_test(), or
  4323. // false if depth-test rendering has been specifically
  4324. // disabled, or if nothing has been specifically set. See
  4325. // also has_depth_test().
  4326. ////////////////////////////////////////////////////////////////////
  4327. bool NodePath::
  4328. get_depth_test() const {
  4329. nassertr_always(!is_empty(), false);
  4330. const RenderAttrib *attrib =
  4331. node()->get_attrib(DepthTestAttrib::get_class_type());
  4332. if (attrib != (const RenderAttrib *)NULL) {
  4333. const DepthTestAttrib *dta = DCAST(DepthTestAttrib, attrib);
  4334. return (dta->get_mode() != DepthTestAttrib::M_none);
  4335. }
  4336. return false;
  4337. }
  4338. ////////////////////////////////////////////////////////////////////
  4339. // Function: NodePath::set_depth_write
  4340. // Access: Published
  4341. // Description: Specifically sets or disables the writing to the
  4342. // depth buffer on this particular node. This is
  4343. // normally on in the 3-d scene graph and off in the 2-d
  4344. // scene graph; it should be on for rendering most 3-d
  4345. // objects properly.
  4346. ////////////////////////////////////////////////////////////////////
  4347. void NodePath::
  4348. set_depth_write(bool depth_write, int priority) {
  4349. nassertv_always(!is_empty());
  4350. DepthWriteAttrib::Mode mode =
  4351. depth_write ?
  4352. DepthWriteAttrib::M_on :
  4353. DepthWriteAttrib::M_off;
  4354. node()->set_attrib(DepthWriteAttrib::make(mode), priority);
  4355. }
  4356. ////////////////////////////////////////////////////////////////////
  4357. // Function: NodePath::clear_depth_write
  4358. // Access: Published
  4359. // Description: Completely removes any depth-write adjustment that
  4360. // may have been set on this node via set_depth_write().
  4361. ////////////////////////////////////////////////////////////////////
  4362. void NodePath::
  4363. clear_depth_write() {
  4364. nassertv_always(!is_empty());
  4365. node()->clear_attrib(DepthWriteAttrib::get_class_type());
  4366. }
  4367. ////////////////////////////////////////////////////////////////////
  4368. // Function: NodePath::has_depth_write
  4369. // Access: Published
  4370. // Description: Returns true if a depth-write adjustment has been
  4371. // explicitly set on this particular node via
  4372. // set_depth_write(). If this returns true, then
  4373. // get_depth_write() may be called to determine which has
  4374. // been set.
  4375. ////////////////////////////////////////////////////////////////////
  4376. bool NodePath::
  4377. has_depth_write() const {
  4378. nassertr_always(!is_empty(), false);
  4379. return node()->has_attrib(DepthWriteAttrib::get_class_type());
  4380. }
  4381. ////////////////////////////////////////////////////////////////////
  4382. // Function: NodePath::get_depth_write
  4383. // Access: Published
  4384. // Description: Returns true if depth-write rendering has been
  4385. // specifically set on this node via set_depth_write(), or
  4386. // false if depth-write rendering has been specifically
  4387. // disabled, or if nothing has been specifically set. See
  4388. // also has_depth_write().
  4389. ////////////////////////////////////////////////////////////////////
  4390. bool NodePath::
  4391. get_depth_write() const {
  4392. nassertr_always(!is_empty(), false);
  4393. const RenderAttrib *attrib =
  4394. node()->get_attrib(DepthWriteAttrib::get_class_type());
  4395. if (attrib != (const RenderAttrib *)NULL) {
  4396. const DepthWriteAttrib *dta = DCAST(DepthWriteAttrib, attrib);
  4397. return (dta->get_mode() != DepthWriteAttrib::M_off);
  4398. }
  4399. return false;
  4400. }
  4401. ////////////////////////////////////////////////////////////////////
  4402. // Function: NodePath::do_billboard_axis
  4403. // Access: Published
  4404. // Description: Performs a billboard-type rotate to the indicated
  4405. // camera node, one time only, and leaves the object
  4406. // rotated. This is similar in principle to heads_up().
  4407. ////////////////////////////////////////////////////////////////////
  4408. void NodePath::
  4409. do_billboard_axis(const NodePath &camera, float offset) {
  4410. nassertv_always(!is_empty());
  4411. CPT(TransformState) transform = camera.get_transform(get_parent());
  4412. const LMatrix4f &rel_mat = transform->get_mat();
  4413. LVector3f up = LVector3f::up();
  4414. LVector3f rel_pos = -rel_mat.get_row3(3);
  4415. LQuaternionf quat;
  4416. ::heads_up(quat, rel_pos, up);
  4417. set_quat(quat);
  4418. // Also slide the geometry towards the camera according to the
  4419. // offset factor.
  4420. if (offset != 0.0f) {
  4421. LVector3f translate = rel_mat.get_row3(3);
  4422. translate.normalize();
  4423. translate *= offset;
  4424. set_pos(translate);
  4425. }
  4426. }
  4427. ////////////////////////////////////////////////////////////////////
  4428. // Function: NodePath::do_billboard_point_eye
  4429. // Access: Published
  4430. // Description: Performs a billboard-type rotate to the indicated
  4431. // camera node, one time only, and leaves the object
  4432. // rotated. This is similar in principle to look_at(),
  4433. // although the point_eye billboard effect cannot be
  4434. // achieved using the ordinary look_at() call.
  4435. ////////////////////////////////////////////////////////////////////
  4436. void NodePath::
  4437. do_billboard_point_eye(const NodePath &camera, float offset) {
  4438. nassertv_always(!is_empty());
  4439. CPT(TransformState) transform = camera.get_transform(get_parent());
  4440. const LMatrix4f &rel_mat = transform->get_mat();
  4441. LVector3f up = LVector3f::up() * rel_mat;
  4442. LVector3f rel_pos = LVector3f::forward() * rel_mat;
  4443. LQuaternionf quat;
  4444. ::look_at(quat, rel_pos, up);
  4445. set_quat(quat);
  4446. // Also slide the geometry towards the camera according to the
  4447. // offset factor.
  4448. if (offset != 0.0f) {
  4449. LVector3f translate = rel_mat.get_row3(3);
  4450. translate.normalize();
  4451. translate *= offset;
  4452. set_pos(translate);
  4453. }
  4454. }
  4455. ////////////////////////////////////////////////////////////////////
  4456. // Function: NodePath::do_billboard_point_world
  4457. // Access: Published
  4458. // Description: Performs a billboard-type rotate to the indicated
  4459. // camera node, one time only, and leaves the object
  4460. // rotated. This is similar in principle to look_at().
  4461. ////////////////////////////////////////////////////////////////////
  4462. void NodePath::
  4463. do_billboard_point_world(const NodePath &camera, float offset) {
  4464. nassertv_always(!is_empty());
  4465. CPT(TransformState) transform = camera.get_transform(get_parent());
  4466. const LMatrix4f &rel_mat = transform->get_mat();
  4467. LVector3f up = LVector3f::up();
  4468. LVector3f rel_pos = -rel_mat.get_row3(3);
  4469. LQuaternionf quat;
  4470. ::look_at(quat, rel_pos, up);
  4471. set_quat(quat);
  4472. // Also slide the geometry towards the camera according to the
  4473. // offset factor.
  4474. if (offset != 0.0f) {
  4475. LVector3f translate = rel_mat.get_row3(3);
  4476. translate.normalize();
  4477. translate *= offset;
  4478. set_pos(translate);
  4479. }
  4480. }
  4481. ////////////////////////////////////////////////////////////////////
  4482. // Function: NodePath::set_billboard_axis
  4483. // Access: Published
  4484. // Description: Puts a billboard transition on the node such that it
  4485. // will rotate in two dimensions around the up axis,
  4486. // towards a specified "camera" instead of to the
  4487. // viewing camera.
  4488. ////////////////////////////////////////////////////////////////////
  4489. void NodePath::
  4490. set_billboard_axis(const NodePath &camera, float offset) {
  4491. nassertv_always(!is_empty());
  4492. CPT(RenderEffect) billboard = BillboardEffect::make
  4493. (LVector3f::up(), false, true,
  4494. offset, camera, LPoint3f(0.0f, 0.0f, 0.0f));
  4495. node()->set_effect(billboard);
  4496. }
  4497. ////////////////////////////////////////////////////////////////////
  4498. // Function: NodePath::set_billboard_point_eye
  4499. // Access: Published
  4500. // Description: Puts a billboard transition on the node such that it
  4501. // will rotate in three dimensions about the origin,
  4502. // keeping its up vector oriented to the top of the
  4503. // camera, towards a specified "camera" instead of to
  4504. // the viewing camera.
  4505. ////////////////////////////////////////////////////////////////////
  4506. void NodePath::
  4507. set_billboard_point_eye(const NodePath &camera, float offset) {
  4508. nassertv_always(!is_empty());
  4509. CPT(RenderEffect) billboard = BillboardEffect::make
  4510. (LVector3f::up(), true, false,
  4511. offset, camera, LPoint3f(0.0f, 0.0f, 0.0f));
  4512. node()->set_effect(billboard);
  4513. }
  4514. ////////////////////////////////////////////////////////////////////
  4515. // Function: NodePath::set_billboard_point_world
  4516. // Access: Published
  4517. // Description: Puts a billboard transition on the node such that it
  4518. // will rotate in three dimensions about the origin,
  4519. // keeping its up vector oriented to the sky, towards a
  4520. // specified "camera" instead of to the viewing camera.
  4521. ////////////////////////////////////////////////////////////////////
  4522. void NodePath::
  4523. set_billboard_point_world(const NodePath &camera, float offset) {
  4524. nassertv_always(!is_empty());
  4525. CPT(RenderEffect) billboard = BillboardEffect::make
  4526. (LVector3f::up(), false, false,
  4527. offset, camera, LPoint3f(0.0f, 0.0f, 0.0f));
  4528. node()->set_effect(billboard);
  4529. }
  4530. ////////////////////////////////////////////////////////////////////
  4531. // Function: NodePath::clear_billboard
  4532. // Access: Published
  4533. // Description: Removes any billboard effect from the node.
  4534. ////////////////////////////////////////////////////////////////////
  4535. void NodePath::
  4536. clear_billboard() {
  4537. nassertv_always(!is_empty());
  4538. node()->clear_effect(BillboardEffect::get_class_type());
  4539. }
  4540. ////////////////////////////////////////////////////////////////////
  4541. // Function: NodePath::has_billboard
  4542. // Access: Published
  4543. // Description: Returns true if there is any billboard effect on
  4544. // the node.
  4545. ////////////////////////////////////////////////////////////////////
  4546. bool NodePath::
  4547. has_billboard() const {
  4548. nassertr_always(!is_empty(), false);
  4549. return node()->has_effect(BillboardEffect::get_class_type());
  4550. }
  4551. ////////////////////////////////////////////////////////////////////
  4552. // Function: NodePath::set_compass
  4553. // Access: Published
  4554. // Description: Puts a compass effect on the node, so that it will
  4555. // retain a fixed rotation relative to the reference
  4556. // node (or render if the reference node is empty)
  4557. // regardless of the transforms above it.
  4558. ////////////////////////////////////////////////////////////////////
  4559. void NodePath::
  4560. set_compass(const NodePath &reference) {
  4561. nassertv_always(!is_empty());
  4562. node()->set_effect(CompassEffect::make(reference));
  4563. }
  4564. ////////////////////////////////////////////////////////////////////
  4565. // Function: NodePath::clear_compass
  4566. // Access: Published
  4567. // Description: Removes any compass effect from the node.
  4568. ////////////////////////////////////////////////////////////////////
  4569. void NodePath::
  4570. clear_compass() {
  4571. nassertv_always(!is_empty());
  4572. node()->clear_effect(CompassEffect::get_class_type());
  4573. }
  4574. ////////////////////////////////////////////////////////////////////
  4575. // Function: NodePath::has_compass
  4576. // Access: Published
  4577. // Description: Returns true if there is any compass effect on
  4578. // the node.
  4579. ////////////////////////////////////////////////////////////////////
  4580. bool NodePath::
  4581. has_compass() const {
  4582. nassertr_always(!is_empty(), false);
  4583. return node()->has_effect(CompassEffect::get_class_type());
  4584. }
  4585. ////////////////////////////////////////////////////////////////////
  4586. // Function: NodePath::set_transparency
  4587. // Access: Published
  4588. // Description: Specifically sets or disables transparent rendering
  4589. // mode on this particular node. If no other nodes
  4590. // override, this will cause items with a non-1 value
  4591. // for alpha color to be rendered partially transparent.
  4592. ////////////////////////////////////////////////////////////////////
  4593. void NodePath::
  4594. set_transparency(TransparencyAttrib::Mode mode, int priority) {
  4595. nassertv_always(!is_empty());
  4596. node()->set_attrib(TransparencyAttrib::make(mode), priority);
  4597. }
  4598. ////////////////////////////////////////////////////////////////////
  4599. // Function: NodePath::clear_transparency
  4600. // Access: Published
  4601. // Description: Completely removes any transparency adjustment that
  4602. // may have been set on this node via set_transparency().
  4603. // The geometry at this level and below will
  4604. // subsequently be rendered either transparent or not,
  4605. // to whatever other nodes may have had
  4606. // set_transparency() on them.
  4607. ////////////////////////////////////////////////////////////////////
  4608. void NodePath::
  4609. clear_transparency() {
  4610. nassertv_always(!is_empty());
  4611. node()->clear_attrib(TransparencyAttrib::get_class_type());
  4612. }
  4613. ////////////////////////////////////////////////////////////////////
  4614. // Function: NodePath::has_transparency
  4615. // Access: Published
  4616. // Description: Returns true if a transparent-rendering adjustment
  4617. // has been explicitly set on this particular node via
  4618. // set_transparency(). If this returns true, then
  4619. // get_transparency() may be called to determine whether
  4620. // transparency has been explicitly enabled or
  4621. // explicitly disabled for this node.
  4622. ////////////////////////////////////////////////////////////////////
  4623. bool NodePath::
  4624. has_transparency() const {
  4625. nassertr_always(!is_empty(), false);
  4626. return node()->has_attrib(TransparencyAttrib::get_class_type());
  4627. }
  4628. ////////////////////////////////////////////////////////////////////
  4629. // Function: NodePath::get_transparency
  4630. // Access: Published
  4631. // Description: Returns the transparent rendering that has been
  4632. // specifically set on this node via set_transparency(), or
  4633. // M_none if nontransparent rendering has been specifically
  4634. // set, or if nothing has been specifically set. See
  4635. // also has_transparency(). This does not necessarily
  4636. // imply that the geometry will or will not be rendered
  4637. // transparent, as there may be other nodes that override.
  4638. ////////////////////////////////////////////////////////////////////
  4639. TransparencyAttrib::Mode NodePath::
  4640. get_transparency() const {
  4641. nassertr_always(!is_empty(), TransparencyAttrib::M_none);
  4642. const RenderAttrib *attrib =
  4643. node()->get_attrib(TransparencyAttrib::get_class_type());
  4644. if (attrib != (const RenderAttrib *)NULL) {
  4645. const TransparencyAttrib *ta = DCAST(TransparencyAttrib, attrib);
  4646. return ta->get_mode();
  4647. }
  4648. return TransparencyAttrib::M_none;
  4649. }
  4650. ////////////////////////////////////////////////////////////////////
  4651. // Function: NodePath::set_antialias
  4652. // Access: Published
  4653. // Description: Specifies the antialiasing type that should be
  4654. // applied at this node and below. See AntialiasAttrib.
  4655. ////////////////////////////////////////////////////////////////////
  4656. void NodePath::
  4657. set_antialias(unsigned short mode, int priority) {
  4658. nassertv_always(!is_empty());
  4659. node()->set_attrib(AntialiasAttrib::make(mode), priority);
  4660. }
  4661. ////////////////////////////////////////////////////////////////////
  4662. // Function: NodePath::clear_antialias
  4663. // Access: Published
  4664. // Description: Completely removes any antialias setting that
  4665. // may have been set on this node via set_antialias().
  4666. ////////////////////////////////////////////////////////////////////
  4667. void NodePath::
  4668. clear_antialias() {
  4669. nassertv_always(!is_empty());
  4670. node()->clear_attrib(AntialiasAttrib::get_class_type());
  4671. }
  4672. ////////////////////////////////////////////////////////////////////
  4673. // Function: NodePath::has_antialias
  4674. // Access: Published
  4675. // Description: Returns true if an antialias setting has been
  4676. // explicitly mode on this particular node via
  4677. // set_antialias(). If this returns true, then
  4678. // get_antialias() may be called to determine what the
  4679. // setting was.
  4680. ////////////////////////////////////////////////////////////////////
  4681. bool NodePath::
  4682. has_antialias() const {
  4683. nassertr_always(!is_empty(), false);
  4684. return node()->has_attrib(AntialiasAttrib::get_class_type());
  4685. }
  4686. ////////////////////////////////////////////////////////////////////
  4687. // Function: NodePath::get_antialias
  4688. // Access: Published
  4689. // Description: Returns the antialias setting that has been
  4690. // specifically set on this node via set_antialias(), or
  4691. // M_none if no setting has been made.
  4692. ////////////////////////////////////////////////////////////////////
  4693. unsigned short NodePath::
  4694. get_antialias() const {
  4695. nassertr_always(!is_empty(), AntialiasAttrib::M_none);
  4696. const RenderAttrib *attrib =
  4697. node()->get_attrib(AntialiasAttrib::get_class_type());
  4698. if (attrib != (const RenderAttrib *)NULL) {
  4699. const AntialiasAttrib *ta = DCAST(AntialiasAttrib, attrib);
  4700. return ta->get_mode();
  4701. }
  4702. return AntialiasAttrib::M_none;
  4703. }
  4704. ////////////////////////////////////////////////////////////////////
  4705. // Function: NodePath::has_audio_volume
  4706. // Access: Published
  4707. // Description: Returns true if an audio volume has been applied
  4708. // to the referenced node, false otherwise. It is still
  4709. // possible that volume at this node might have been
  4710. // scaled by an ancestor node.
  4711. ////////////////////////////////////////////////////////////////////
  4712. bool NodePath::
  4713. has_audio_volume() const {
  4714. nassertr_always(!is_empty(), false);
  4715. return node()->has_attrib(AudioVolumeAttrib::get_class_type());
  4716. }
  4717. ////////////////////////////////////////////////////////////////////
  4718. // Function: NodePath::clear_audio_volume
  4719. // Access: Published
  4720. // Description: Completely removes any audio volume from the
  4721. // referenced node. This is preferable to simply
  4722. // setting the audio volume to identity, as it also
  4723. // removes the overhead associated with having an audio
  4724. // volume at all.
  4725. ////////////////////////////////////////////////////////////////////
  4726. void NodePath::
  4727. clear_audio_volume() {
  4728. nassertv_always(!is_empty());
  4729. node()->clear_attrib(AudioVolumeAttrib::get_class_type());
  4730. }
  4731. ////////////////////////////////////////////////////////////////////
  4732. // Function: NodePath::set_audio_volume
  4733. // Access: Published
  4734. // Description: Sets the audio volume component of the transform
  4735. ////////////////////////////////////////////////////////////////////
  4736. void NodePath::
  4737. set_audio_volume(float volume, int priority) {
  4738. nassertv_always(!is_empty());
  4739. const RenderAttrib *attrib =
  4740. node()->get_attrib(AudioVolumeAttrib::get_class_type());
  4741. if (attrib != (const RenderAttrib *)NULL) {
  4742. priority = max(priority,
  4743. node()->get_state()->get_override(AudioVolumeAttrib::get_class_type()));
  4744. CPT(AudioVolumeAttrib) ava = DCAST(AudioVolumeAttrib, attrib);
  4745. // Modify the existing AudioVolumeAttrib to add the indicated
  4746. // volume.
  4747. node()->set_attrib(ava->set_volume(volume), priority);
  4748. } else {
  4749. // Create a new AudioVolumeAttrib for this node.
  4750. node()->set_attrib(AudioVolumeAttrib::make(volume), priority);
  4751. }
  4752. }
  4753. ////////////////////////////////////////////////////////////////////
  4754. // Function: NodePath::set_audio_volume_off
  4755. // Access: Published
  4756. // Description: Disables any audio volume attribute inherited from
  4757. // above. This is not the same thing as
  4758. // clear_audio_volume(), which undoes any previous
  4759. // set_audio_volume() operation on this node; rather,
  4760. // this actively disables any set_audio_volume() that
  4761. // might be inherited from a parent node.
  4762. //
  4763. // It is legal to specify a new volume on the same
  4764. // node with a subsequent call to set_audio_volume();
  4765. // this new scale will apply to lower nodes.
  4766. ////////////////////////////////////////////////////////////////////
  4767. void NodePath::
  4768. set_audio_volume_off(int priority) {
  4769. nassertv_always(!is_empty());
  4770. node()->set_attrib(AudioVolumeAttrib::make_off(), priority);
  4771. }
  4772. ////////////////////////////////////////////////////////////////////
  4773. // Function: NodePath::get_audio_volume
  4774. // Access: Published
  4775. // Description: Returns the complete audio volume that has been
  4776. // applied to this node via a previous call to
  4777. // set_audio_volume(), or 1. (identity) if no volume has
  4778. // been applied to this particular node.
  4779. ////////////////////////////////////////////////////////////////////
  4780. float NodePath::
  4781. get_audio_volume() const {
  4782. const RenderAttrib *attrib =
  4783. node()->get_attrib(AudioVolumeAttrib::get_class_type());
  4784. if (attrib != (const RenderAttrib *)NULL) {
  4785. const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
  4786. return ava->get_volume();
  4787. }
  4788. return 1.0f;
  4789. }
  4790. ////////////////////////////////////////////////////////////////////
  4791. // Function: NodePath::get_net_audio_volume
  4792. // Access: Published
  4793. // Description: Returns the complete audio volume for this node
  4794. // taking highers nodes in the graph into account.
  4795. ////////////////////////////////////////////////////////////////////
  4796. float NodePath::
  4797. get_net_audio_volume() const {
  4798. CPT(RenderState) net_state = get_net_state();
  4799. const RenderAttrib *attrib = net_state->get_audio_volume();
  4800. if (attrib != (const RenderAttrib *)NULL) {
  4801. const AudioVolumeAttrib *ava = DCAST(AudioVolumeAttrib, attrib);
  4802. if (ava != (const AudioVolumeAttrib *)NULL) {
  4803. return ava->get_volume();
  4804. }
  4805. }
  4806. return 1.0f;
  4807. }
  4808. ////////////////////////////////////////////////////////////////////
  4809. // Function: NodePath::get_hidden_ancestor
  4810. // Access: Published
  4811. // Description: Returns the NodePath at or above the referenced node
  4812. // that is hidden to the indicated camera(s), or an
  4813. // empty NodePath if no ancestor of the referenced node
  4814. // is hidden (and the node should be visible).
  4815. ////////////////////////////////////////////////////////////////////
  4816. NodePath NodePath::
  4817. get_hidden_ancestor(DrawMask camera_mask, Thread *current_thread) const {
  4818. int pipeline_stage = current_thread->get_pipeline_stage();
  4819. NodePathComponent *comp;
  4820. for (comp = _head;
  4821. comp != (NodePathComponent *)NULL;
  4822. comp = comp->get_next(pipeline_stage, current_thread)) {
  4823. PandaNode *node = comp->get_node();
  4824. if (node->is_overall_hidden() ||
  4825. ((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) {
  4826. NodePath result;
  4827. result._head = comp;
  4828. return result;
  4829. }
  4830. }
  4831. return not_found();
  4832. }
  4833. ////////////////////////////////////////////////////////////////////
  4834. // Function: NodePath::stash
  4835. // Access: Published
  4836. // Description: Removes the referenced node (and the entire subgraph
  4837. // below this node) from the scene graph in any normal
  4838. // sense. The node will no longer be visible and is not
  4839. // tested for collisions; furthermore, no normal scene
  4840. // graph traversal will visit the node. The node's
  4841. // bounding volume no longer contributes to its parent's
  4842. // bounding volume.
  4843. //
  4844. // A stashed node cannot be located by a normal find()
  4845. // operation (although a special find string can still
  4846. // retrieve it).
  4847. ////////////////////////////////////////////////////////////////////
  4848. void NodePath::
  4849. stash(int sort, Thread *current_thread) {
  4850. nassertv_always(!is_singleton() && !is_empty());
  4851. nassertv(verify_complete());
  4852. int pipeline_stage = current_thread->get_pipeline_stage();
  4853. bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
  4854. _head, sort, true, pipeline_stage,
  4855. current_thread);
  4856. nassertv(reparented);
  4857. }
  4858. ////////////////////////////////////////////////////////////////////
  4859. // Function: NodePath::unstash
  4860. // Access: Published
  4861. // Description: Undoes the effect of a previous stash() on this
  4862. // node: makes the referenced node (and the entire
  4863. // subgraph below this node) once again part of the
  4864. // scene graph.
  4865. ////////////////////////////////////////////////////////////////////
  4866. void NodePath::
  4867. unstash(int sort, Thread *current_thread) {
  4868. nassertv_always(!is_singleton() && !is_empty());
  4869. nassertv(verify_complete());
  4870. int pipeline_stage = current_thread->get_pipeline_stage();
  4871. bool reparented = PandaNode::reparent(_head->get_next(pipeline_stage, current_thread),
  4872. _head, sort, false, pipeline_stage,
  4873. current_thread);
  4874. nassertv(reparented);
  4875. }
  4876. ////////////////////////////////////////////////////////////////////
  4877. // Function: NodePath::unstash_all
  4878. // Access: Published
  4879. // Description: Unstashes this node and all stashed child nodes.
  4880. ////////////////////////////////////////////////////////////////////
  4881. void NodePath::
  4882. unstash_all(Thread *current_thread) {
  4883. NodePathCollection stashed_descendents = find_all_matches("**/@@*");
  4884. stashed_descendents.unstash();
  4885. unstash(0, current_thread);
  4886. }
  4887. ////////////////////////////////////////////////////////////////////
  4888. // Function: NodePath::get_stashed_ancestor
  4889. // Access: Published
  4890. // Description: Returns the NodePath at or above the referenced node
  4891. // that is stashed, or an empty NodePath if no ancestor
  4892. // of the referenced node is stashed (and the node should
  4893. // be visible).
  4894. ////////////////////////////////////////////////////////////////////
  4895. NodePath NodePath::
  4896. get_stashed_ancestor(Thread *current_thread) const {
  4897. NodePathComponent *comp = _head;
  4898. if (comp != (NodePathComponent *)NULL) {
  4899. int pipeline_stage = current_thread->get_pipeline_stage();
  4900. NodePathComponent *next = comp->get_next(pipeline_stage, current_thread);
  4901. while (next != (NodePathComponent *)NULL) {
  4902. PandaNode *node = comp->get_node();
  4903. PandaNode *parent_node = next->get_node();
  4904. if (parent_node->find_stashed(node) >= 0) {
  4905. NodePath result;
  4906. result._head = comp;
  4907. return result;
  4908. }
  4909. comp = next;
  4910. next = next->get_next(pipeline_stage, current_thread);
  4911. }
  4912. }
  4913. return not_found();
  4914. }
  4915. ////////////////////////////////////////////////////////////////////
  4916. // Function: NodePath::verify_complete
  4917. // Access: Published
  4918. // Description: Returns true if all of the nodes described in the
  4919. // NodePath are connected, or false otherwise.
  4920. ////////////////////////////////////////////////////////////////////
  4921. bool NodePath::
  4922. verify_complete(Thread *current_thread) const {
  4923. if (is_empty()) {
  4924. return true;
  4925. }
  4926. const NodePathComponent *comp = _head;
  4927. nassertr(comp != (const NodePathComponent *)NULL, false);
  4928. int pipeline_stage = current_thread->get_pipeline_stage();
  4929. PandaNode *node = comp->get_node();
  4930. nassertr(node != (const PandaNode *)NULL, false);
  4931. int length = comp->get_length(pipeline_stage, current_thread);
  4932. comp = comp->get_next(pipeline_stage, current_thread);
  4933. length--;
  4934. while (comp != (const NodePathComponent *)NULL) {
  4935. PandaNode *next_node = comp->get_node();
  4936. nassertr(next_node != (const PandaNode *)NULL, false);
  4937. if (node->find_parent(next_node) < 0) {
  4938. pgraph_cat.warning()
  4939. << *this << " is incomplete; " << *node << " is not a child of "
  4940. << *next_node << "\n";
  4941. return false;
  4942. }
  4943. if (comp->get_length(pipeline_stage, current_thread) != length) {
  4944. pgraph_cat.warning()
  4945. << *this << " is incomplete; length at " << *next_node
  4946. << " indicates " << comp->get_length(pipeline_stage, current_thread)
  4947. << " while length at " << *node << " indicates " << length << "\n";
  4948. return false;
  4949. }
  4950. node = next_node;
  4951. comp = comp->get_next(pipeline_stage, current_thread);
  4952. length--;
  4953. }
  4954. return true;
  4955. }
  4956. ////////////////////////////////////////////////////////////////////
  4957. // Function: NodePath::prepare_scene
  4958. // Access: Published
  4959. // Description: Walks through the scene graph beginning at the bottom
  4960. // node, and does whatever initialization is required to
  4961. // render the scene properly with the indicated GSG. It
  4962. // is not strictly necessary to call this, since the GSG
  4963. // will initialize itself when the scene is rendered,
  4964. // but this may take some of the overhead away from that
  4965. // process.
  4966. //
  4967. // In particular, this will ensure that textures within
  4968. // the scene are loaded in texture memory, and display
  4969. // lists are built up from static geometry.
  4970. ////////////////////////////////////////////////////////////////////
  4971. void NodePath::
  4972. prepare_scene(GraphicsStateGuardianBase *gsg) {
  4973. nassertv_always(!is_empty());
  4974. PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects();
  4975. CPT(RenderState) net_state = get_net_state();
  4976. r_prepare_scene(node(), net_state, prepared_objects);
  4977. }
  4978. ////////////////////////////////////////////////////////////////////
  4979. // Function: NodePath::show_bounds
  4980. // Access: Published
  4981. // Description: Causes the bounding volume of the bottom node and all
  4982. // of its descendants (that is, the bounding volume
  4983. // associated with the the bottom arc) to be rendered,
  4984. // if possible. The rendering method is less than
  4985. // optimal; this is intended primarily for debugging.
  4986. ////////////////////////////////////////////////////////////////////
  4987. void NodePath::
  4988. show_bounds() {
  4989. nassertv_always(!is_empty());
  4990. node()->set_effect(ShowBoundsEffect::make(false));
  4991. }
  4992. ////////////////////////////////////////////////////////////////////
  4993. // Function: NodePath::show_tight_bounds
  4994. // Access: Published
  4995. // Description: Similar to show_bounds(), this draws a bounding box
  4996. // representing the "tight" bounds of this node and all
  4997. // of its descendants. The bounding box is recomputed
  4998. // every frame by reexamining all of the vertices; this
  4999. // is far from efficient, but this is intended for
  5000. // debugging.
  5001. ////////////////////////////////////////////////////////////////////
  5002. void NodePath::
  5003. show_tight_bounds() {
  5004. nassertv_always(!is_empty());
  5005. node()->set_effect(ShowBoundsEffect::make(true));
  5006. }
  5007. ////////////////////////////////////////////////////////////////////
  5008. // Function: NodePath::hide_bounds
  5009. // Access: Published
  5010. // Description: Stops the rendering of the bounding volume begun with
  5011. // show_bounds().
  5012. ////////////////////////////////////////////////////////////////////
  5013. void NodePath::
  5014. hide_bounds() {
  5015. nassertv_always(!is_empty());
  5016. node()->clear_effect(ShowBoundsEffect::get_class_type());
  5017. }
  5018. ////////////////////////////////////////////////////////////////////
  5019. // Function: NodePath::get_bounds
  5020. // Access: Published
  5021. // Description: Returns a newly-allocated bounding volume containing
  5022. // the bottom node and all of its descendants. This is
  5023. // the bounding volume on the bottom arc, converted to
  5024. // the local coordinate space of the node.
  5025. ////////////////////////////////////////////////////////////////////
  5026. PT(BoundingVolume) NodePath::
  5027. get_bounds(Thread *current_thread) const {
  5028. nassertr_always(!is_empty(), new BoundingSphere);
  5029. return node()->get_bounds(current_thread)->make_copy();
  5030. }
  5031. ////////////////////////////////////////////////////////////////////
  5032. // Function: NodePath::force_recompute_bounds
  5033. // Access: Published
  5034. // Description: Forces the recomputing of all the bounding volumes at
  5035. // every node in the subgraph beginning at this node and
  5036. // below.
  5037. //
  5038. // This should not normally need to be called, since the
  5039. // bounding volumes are supposed to be recomputed
  5040. // automatically when necessary. It may be useful when
  5041. // debugging, to verify that the bounding volumes have
  5042. // not become inadvertently stale; it may also be useful
  5043. // to force animated characters to update their bounding
  5044. // volumes (which does not presently happen
  5045. // automatically).
  5046. ////////////////////////////////////////////////////////////////////
  5047. void NodePath::
  5048. force_recompute_bounds() {
  5049. nassertv_always(!is_empty());
  5050. r_force_recompute_bounds(node());
  5051. }
  5052. ////////////////////////////////////////////////////////////////////
  5053. // Function: NodePath::write_bounds
  5054. // Access: Published
  5055. // Description: Writes a description of the bounding volume
  5056. // containing the bottom node and all of its descendants
  5057. // to the indicated output stream.
  5058. ////////////////////////////////////////////////////////////////////
  5059. void NodePath::
  5060. write_bounds(ostream &out) const {
  5061. get_bounds()->write(out);
  5062. }
  5063. ////////////////////////////////////////////////////////////////////
  5064. // Function: NodePath::calc_tight_bounds
  5065. // Access: Published
  5066. // Description: Calculates the minimum and maximum vertices of all
  5067. // Geoms at this NodePath's bottom node and below. This
  5068. // is a tight bounding box; it will generally be tighter
  5069. // than the bounding volume returned by get_bounds()
  5070. // (but it is more expensive to compute).
  5071. //
  5072. // The return value is true if any points are within the
  5073. // bounding volume, or false if none are.
  5074. ////////////////////////////////////////////////////////////////////
  5075. bool NodePath::
  5076. calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
  5077. Thread *current_thread) const {
  5078. min_point.set(0.0f, 0.0f, 0.0f);
  5079. max_point.set(0.0f, 0.0f, 0.0f);
  5080. nassertr_always(!is_empty(), false);
  5081. bool found_any = false;
  5082. node()->calc_tight_bounds(min_point, max_point, found_any,
  5083. TransformState::make_identity(),
  5084. current_thread);
  5085. return found_any;
  5086. }
  5087. ////////////////////////////////////////////////////////////////////
  5088. // Function: NodePath::analyze
  5089. // Access: Published
  5090. // Description: Analyzes the geometry below this node and reports the
  5091. // number of vertices, triangles, etc. This is the same
  5092. // information reported by the bam-info program.
  5093. ////////////////////////////////////////////////////////////////////
  5094. void NodePath::
  5095. analyze() const {
  5096. nassertv_always(!is_empty());
  5097. SceneGraphAnalyzer sga;
  5098. sga.add_node(node());
  5099. sga.write(nout);
  5100. }
  5101. ////////////////////////////////////////////////////////////////////
  5102. // Function: NodePath::flatten_light
  5103. // Access: Published
  5104. // Description: Lightly flattens out the hierarchy below this node by
  5105. // applying transforms, colors, and texture matrices
  5106. // from the arcs onto the vertices, but does not remove
  5107. // any nodes.
  5108. //
  5109. // This can result in improved rendering performance
  5110. // because there will be fewer transforms in the
  5111. // resulting scene graph, but the number of nodes will
  5112. // remain the same.
  5113. //
  5114. // Particularly, any NodePaths that reference nodes
  5115. // within this hierarchy will not be damaged. However,
  5116. // since this operation will remove transforms from the
  5117. // scene graph, it may be dangerous to apply to arcs
  5118. // where you expect to dynamically modify the transform,
  5119. // or where you expect the geometry to remain in a
  5120. // particular local coordinate system.
  5121. //
  5122. // The return value is always 0, since flatten_light
  5123. // does not remove any arcs.
  5124. ////////////////////////////////////////////////////////////////////
  5125. int NodePath::
  5126. flatten_light() {
  5127. nassertr_always(!is_empty(), 0);
  5128. SceneGraphReducer gr;
  5129. gr.apply_attribs(node());
  5130. return 0;
  5131. }
  5132. ////////////////////////////////////////////////////////////////////
  5133. // Function: NodePath::flatten_medium
  5134. // Access: Published
  5135. // Description: A more thorough flattening than flatten_light(), this
  5136. // first applies all the transforms, colors, and texture
  5137. // matrices from the arcs onto the vertices, and then
  5138. // removes unneeded grouping nodes--nodes that have
  5139. // exactly one child, for instance, but have no special
  5140. // properties in themselves.
  5141. //
  5142. // This results in improved perforamance over
  5143. // flatten_light() because the number of nodes in the
  5144. // scene graph is reduced.
  5145. //
  5146. // If max_children is specified, it represents the
  5147. // maximum number of children a node is allowed to have
  5148. // and still be flattened. Normally, this is 1; we
  5149. // don't typically want to flatten a node that has
  5150. // multiple children. However, sometimes this may be
  5151. // desirable; set this parameter to control the limit.
  5152. // If this is set to -1, there is no limit.
  5153. //
  5154. // The return value is the number of arcs removed.
  5155. ////////////////////////////////////////////////////////////////////
  5156. int NodePath::
  5157. flatten_medium() {
  5158. nassertr_always(!is_empty(), 0);
  5159. SceneGraphReducer gr;
  5160. gr.apply_attribs(node());
  5161. int num_removed = gr.flatten(node(), 0);
  5162. gr.collect_vertex_data(node());
  5163. gr.unify(node());
  5164. return num_removed;
  5165. }
  5166. ////////////////////////////////////////////////////////////////////
  5167. // Function: NodePath::flatten_strong
  5168. // Access: Published
  5169. // Description: The strongest possible flattening. This first
  5170. // applies all of the transforms to the vertices, as in
  5171. // flatten_medium(), but then it will combine sibling
  5172. // nodes together when possible, in addition to removing
  5173. // unnecessary parent-child nodes. This can result in
  5174. // substantially fewer nodes, but any nicely-grouped
  5175. // hierachical bounding volumes may be lost.
  5176. //
  5177. // It is generally a good idea to apply this kind of
  5178. // flattening only to nodes that will be culled largely
  5179. // as a single unit, like a car. Applying this to an
  5180. // entire scene may result in overall poorer performance
  5181. // because of less-effective culling.
  5182. ////////////////////////////////////////////////////////////////////
  5183. int NodePath::
  5184. flatten_strong() {
  5185. nassertr_always(!is_empty(), 0);
  5186. SceneGraphReducer gr;
  5187. gr.apply_attribs(node());
  5188. int num_removed = gr.flatten(node(), ~0);
  5189. gr.collect_vertex_data(node(), ~(SceneGraphReducer::CVD_format | SceneGraphReducer::CVD_name | SceneGraphReducer::CVD_animation_type));
  5190. gr.unify(node());
  5191. return num_removed;
  5192. }
  5193. ////////////////////////////////////////////////////////////////////
  5194. // Function: NodePath::find_net_tag
  5195. // Access: Published
  5196. // Description: Returns the lowest ancestor of this node that
  5197. // contains a tag definition with the indicated key, if
  5198. // any, or an empty NodePath if no ancestor of this node
  5199. // contains this tag definition. See set_tag().
  5200. ////////////////////////////////////////////////////////////////////
  5201. NodePath NodePath::
  5202. find_net_tag(const string &key) const {
  5203. if (is_empty()) {
  5204. return NodePath::not_found();
  5205. }
  5206. if (has_tag(key)) {
  5207. return *this;
  5208. }
  5209. return get_parent().find_net_tag(key);
  5210. }
  5211. #ifdef HAVE_PYTHON
  5212. ////////////////////////////////////////////////////////////////////
  5213. // Function: NodePath::find_net_python_tag
  5214. // Access: Published
  5215. // Description: Returns the lowest ancestor of this node that
  5216. // contains a tag definition with the indicated key, if
  5217. // any, or an empty NodePath if no ancestor of this node
  5218. // contains this tag definition. See set_python_tag().
  5219. ////////////////////////////////////////////////////////////////////
  5220. NodePath NodePath::
  5221. find_net_python_tag(const string &key) const {
  5222. if (is_empty()) {
  5223. return NodePath::not_found();
  5224. }
  5225. if (has_python_tag(key)) {
  5226. return *this;
  5227. }
  5228. return get_parent().find_net_python_tag(key);
  5229. }
  5230. #endif // HAVE_PYTHON
  5231. ////////////////////////////////////////////////////////////////////
  5232. // Function: NodePath::write_bam_file
  5233. // Access: Published
  5234. // Description: Writes the contents of this node and below out to a
  5235. // bam file with the indicated filename. This file may
  5236. // then be read in again, as is, at some later point.
  5237. // Returns true if successful, false on some kind of
  5238. // error.
  5239. ////////////////////////////////////////////////////////////////////
  5240. bool NodePath::
  5241. write_bam_file(const string &filename) const {
  5242. nassertr_always(!is_empty(), false);
  5243. BamFile bam_file;
  5244. bool okflag = false;
  5245. if (bam_file.open_write(filename)) {
  5246. if (bam_file.write_object(node())) {
  5247. okflag = true;
  5248. }
  5249. bam_file.close();
  5250. }
  5251. return okflag;
  5252. }
  5253. ////////////////////////////////////////////////////////////////////
  5254. // Function: NodePath::find_common_ancestor
  5255. // Access: Private, Static
  5256. // Description: Walks up from both NodePaths to find the first node
  5257. // that both have in common, if any. Fills a_count and
  5258. // b_count with the number of nodes below the common
  5259. // node in each path.
  5260. //
  5261. // The return value is the NodePathComponent of the node
  5262. // they have in common, or NULL if they have nothing in
  5263. // common.
  5264. ////////////////////////////////////////////////////////////////////
  5265. NodePathComponent *NodePath::
  5266. find_common_ancestor(const NodePath &a, const NodePath &b,
  5267. int &a_count, int &b_count, Thread *current_thread) {
  5268. nassertr(!a.is_empty() && !b.is_empty(), NULL);
  5269. NodePathComponent *ac = a._head;
  5270. NodePathComponent *bc = b._head;
  5271. a_count = 0;
  5272. b_count = 0;
  5273. int pipeline_stage = current_thread->get_pipeline_stage();
  5274. // Shorten up the longer one until they are the same length.
  5275. while (ac->get_length(pipeline_stage, current_thread) > bc->get_length(pipeline_stage, current_thread)) {
  5276. nassertr(ac != (NodePathComponent *)NULL, NULL);
  5277. ac = ac->get_next(pipeline_stage, current_thread);
  5278. a_count++;
  5279. }
  5280. while (bc->get_length(pipeline_stage, current_thread) > ac->get_length(pipeline_stage, current_thread)) {
  5281. nassertr(bc != (NodePathComponent *)NULL, NULL);
  5282. bc = bc->get_next(pipeline_stage, current_thread);
  5283. b_count++;
  5284. }
  5285. // Now shorten them both up until we reach the same component.
  5286. while (ac != bc) {
  5287. // These shouldn't go to NULL unless they both go there together.
  5288. nassertr(ac != (NodePathComponent *)NULL, NULL);
  5289. nassertr(bc != (NodePathComponent *)NULL, NULL);
  5290. ac = ac->get_next(pipeline_stage, current_thread);
  5291. a_count++;
  5292. bc = bc->get_next(pipeline_stage, current_thread);
  5293. b_count++;
  5294. }
  5295. return ac;
  5296. }
  5297. ////////////////////////////////////////////////////////////////////
  5298. // Function: NodePath::r_get_net_state
  5299. // Access: Private
  5300. // Description: Recursively determines the net state changes to the
  5301. // indicated component node from the root of the graph.
  5302. ////////////////////////////////////////////////////////////////////
  5303. CPT(RenderState) NodePath::
  5304. r_get_net_state(NodePathComponent *comp, Thread *current_thread) const {
  5305. if (comp == (NodePathComponent *)NULL) {
  5306. return RenderState::make_empty();
  5307. } else {
  5308. CPT(RenderState) state = comp->get_node()->get_state(current_thread);
  5309. int pipeline_stage = current_thread->get_pipeline_stage();
  5310. return r_get_net_state(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(state);
  5311. }
  5312. }
  5313. ////////////////////////////////////////////////////////////////////
  5314. // Function: NodePath::r_get_partial_state
  5315. // Access: Private
  5316. // Description: Recursively determines the net state changes to the
  5317. // indicated component node from the nth node above it.
  5318. // If n exceeds the length of the path, this returns the
  5319. // net transform from the root of the graph.
  5320. ////////////////////////////////////////////////////////////////////
  5321. CPT(RenderState) NodePath::
  5322. r_get_partial_state(NodePathComponent *comp, int n,
  5323. Thread *current_thread) const {
  5324. if (n == 0 || comp == (NodePathComponent *)NULL) {
  5325. return RenderState::make_empty();
  5326. } else {
  5327. CPT(RenderState) state = comp->get_node()->get_state(current_thread);
  5328. int pipeline_stage = current_thread->get_pipeline_stage();
  5329. return r_get_partial_state(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(state);
  5330. }
  5331. }
  5332. ////////////////////////////////////////////////////////////////////
  5333. // Function: NodePath::r_get_net_transform
  5334. // Access: Private
  5335. // Description: Recursively determines the net transform to the
  5336. // indicated component node from the root of the graph.
  5337. ////////////////////////////////////////////////////////////////////
  5338. CPT(TransformState) NodePath::
  5339. r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const {
  5340. if (comp == (NodePathComponent *)NULL) {
  5341. return TransformState::make_identity();
  5342. } else {
  5343. int pipeline_stage = current_thread->get_pipeline_stage();
  5344. CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread);
  5345. PandaNode *node = comp->get_node();
  5346. CPT(TransformState) transform = node->get_transform(current_thread);
  5347. CPT(RenderEffects) effects = node->get_effects(current_thread);
  5348. if (effects->has_adjust_transform()) {
  5349. effects->adjust_transform(net_transform, transform, node);
  5350. }
  5351. return net_transform->compose(transform);
  5352. }
  5353. }
  5354. ////////////////////////////////////////////////////////////////////
  5355. // Function: NodePath::r_get_partial_transform
  5356. // Access: Private
  5357. // Description: Recursively determines the net transform to the
  5358. // indicated component node from the nth node above it.
  5359. // If n exceeds the length of the path, this returns the
  5360. // net transform from the root of the graph.
  5361. //
  5362. // If any node in the path had a net_transform effect
  5363. // applied, returns NULL--in this case the partial
  5364. // transform cannot be easily determined.
  5365. ////////////////////////////////////////////////////////////////////
  5366. CPT(TransformState) NodePath::
  5367. r_get_partial_transform(NodePathComponent *comp, int n,
  5368. Thread *current_thread) const {
  5369. if (n == 0 || comp == (NodePathComponent *)NULL) {
  5370. return TransformState::make_identity();
  5371. } else {
  5372. if (comp->get_node()->get_effects(current_thread)->has_adjust_transform()) {
  5373. return NULL;
  5374. }
  5375. CPT(TransformState) transform = comp->get_node()->get_transform(current_thread);
  5376. int pipeline_stage = current_thread->get_pipeline_stage();
  5377. CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread);
  5378. if (partial == (const TransformState *)NULL) {
  5379. return NULL;
  5380. }
  5381. return partial->compose(transform);
  5382. }
  5383. }
  5384. ////////////////////////////////////////////////////////////////////
  5385. // Function: NodePath::r_get_net_prev_transform
  5386. // Access: Private
  5387. // Description: Recursively determines the net "previous" transform
  5388. // to the indicated component node from the root of the
  5389. // graph.
  5390. ////////////////////////////////////////////////////////////////////
  5391. CPT(TransformState) NodePath::
  5392. r_get_net_prev_transform(NodePathComponent *comp, Thread *current_thread) const {
  5393. if (comp == (NodePathComponent *)NULL) {
  5394. return TransformState::make_identity();
  5395. } else {
  5396. CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread);
  5397. int pipeline_stage = current_thread->get_pipeline_stage();
  5398. return r_get_net_prev_transform(comp->get_next(pipeline_stage, current_thread), current_thread)->compose(transform);
  5399. }
  5400. }
  5401. ////////////////////////////////////////////////////////////////////
  5402. // Function: NodePath::r_get_partial_prev_transform
  5403. // Access: Private
  5404. // Description: Recursively determines the net "previous" transform
  5405. // to the indicated component node from the nth node
  5406. // above it. If n exceeds the length of the path, this
  5407. // returns the net previous transform from the root of
  5408. // the graph.
  5409. ////////////////////////////////////////////////////////////////////
  5410. CPT(TransformState) NodePath::
  5411. r_get_partial_prev_transform(NodePathComponent *comp, int n, Thread *current_thread) const {
  5412. if (n == 0 || comp == (NodePathComponent *)NULL) {
  5413. return TransformState::make_identity();
  5414. } else {
  5415. CPT(TransformState) transform = comp->get_node()->get_prev_transform(current_thread);
  5416. int pipeline_stage = current_thread->get_pipeline_stage();
  5417. return r_get_partial_prev_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread)->compose(transform);
  5418. }
  5419. }
  5420. ////////////////////////////////////////////////////////////////////
  5421. // Function: NodePath::find_matches
  5422. // Access: Private
  5423. // Description: Finds up to max_matches matches against the given
  5424. // path string from this node and deeper. The
  5425. // max_matches count indicates the maximum number of
  5426. // matches to return, or -1 not to limit the number
  5427. // returned.
  5428. ////////////////////////////////////////////////////////////////////
  5429. void NodePath::
  5430. find_matches(NodePathCollection &result, const string &path,
  5431. int max_matches) const {
  5432. if (is_empty()) {
  5433. pgraph_cat.warning()
  5434. << "Attempt to extend an empty NodePath by '" << path
  5435. << "'.\n";
  5436. return;
  5437. }
  5438. FindApproxPath approx_path;
  5439. if (approx_path.add_string(path)) {
  5440. find_matches(result, approx_path, max_matches);
  5441. }
  5442. }
  5443. ////////////////////////////////////////////////////////////////////
  5444. // Function: NodePath::find_matches
  5445. // Access: Private
  5446. // Description: Finds up to max_matches matches against the given
  5447. // approx_path from this node and deeper. The
  5448. // max_matches count indicates the maximum number of
  5449. // matches to return, or -1 not to limit the number
  5450. // returned.
  5451. ////////////////////////////////////////////////////////////////////
  5452. void NodePath::
  5453. find_matches(NodePathCollection &result, FindApproxPath &approx_path,
  5454. int max_matches) const {
  5455. if (is_empty()) {
  5456. pgraph_cat.warning()
  5457. << "Attempt to extend an empty NodePath by: " << approx_path << ".\n";
  5458. return;
  5459. }
  5460. // We start with just one entry on the level.
  5461. FindApproxLevelEntry *level =
  5462. new FindApproxLevelEntry(WorkingNodePath(*this), approx_path);
  5463. nassertv(level->_node_path.is_valid());
  5464. find_matches(result, level, max_matches);
  5465. }
  5466. ////////////////////////////////////////////////////////////////////
  5467. // Function: NodePath::find_matches
  5468. // Access: Private
  5469. // Description: The fundamental implementation of find_matches(),
  5470. // given a starting level (a linked list of
  5471. // FindApproxLevelEntry objects).
  5472. ////////////////////////////////////////////////////////////////////
  5473. void NodePath::
  5474. find_matches(NodePathCollection &result, FindApproxLevelEntry *level,
  5475. int max_matches) const {
  5476. int num_levels_remaining = _max_search_depth;
  5477. FindApproxLevelEntry *deleted_entries = NULL;
  5478. while (num_levels_remaining > 0 && level != NULL) {
  5479. if (pgraph_cat.is_spam()) {
  5480. pgraph_cat.spam()
  5481. << "find_matches pass: " << result << ", "
  5482. << max_matches << ", " << num_levels_remaining << "\n";
  5483. level->write_level(pgraph_cat.spam(false), 4);
  5484. }
  5485. num_levels_remaining--;
  5486. FindApproxLevelEntry *next_level = NULL;
  5487. // For each node in the current level, build up the set of possible
  5488. // matches in the next level.
  5489. FindApproxLevelEntry *entry = level;
  5490. while (entry != (FindApproxLevelEntry *)NULL) {
  5491. if (entry->consider_node(result, next_level, max_matches, 0)) {
  5492. // If we found the requisite number of matches, we can stop.
  5493. // Delete all remaining entries and return immediately.
  5494. while (entry != (FindApproxLevelEntry *)NULL) {
  5495. FindApproxLevelEntry *next = entry->_next;
  5496. delete entry;
  5497. entry = next;
  5498. }
  5499. while (next_level != (FindApproxLevelEntry *)NULL) {
  5500. FindApproxLevelEntry *next = next_level->_next;
  5501. delete next_level;
  5502. next_level = next;
  5503. }
  5504. while (deleted_entries != (FindApproxLevelEntry *)NULL) {
  5505. FindApproxLevelEntry *next = deleted_entries->_next;
  5506. delete deleted_entries;
  5507. deleted_entries = next;
  5508. }
  5509. return;
  5510. }
  5511. // Move the entry to the delete chain so we can delete it before
  5512. // we return from this method. (We can't delete it immediately,
  5513. // because there might be WorkingNodePaths in the next_level
  5514. // that reference the WorkingNodePath object within the entry.)
  5515. FindApproxLevelEntry *next = entry->_next;
  5516. entry->_next = deleted_entries;
  5517. deleted_entries = entry;
  5518. entry = next;
  5519. }
  5520. // Make sure the remaining entries from this level are added to
  5521. // the delete chain.
  5522. while (entry != (FindApproxLevelEntry *)NULL) {
  5523. FindApproxLevelEntry *next = entry->_next;
  5524. entry->_next = deleted_entries;
  5525. deleted_entries = entry;
  5526. entry = next;
  5527. }
  5528. level = next_level;
  5529. }
  5530. // Now it's safe to delete all entries on the delete chain.
  5531. while (deleted_entries != (FindApproxLevelEntry *)NULL) {
  5532. FindApproxLevelEntry *next = deleted_entries->_next;
  5533. delete deleted_entries;
  5534. deleted_entries = next;
  5535. }
  5536. }
  5537. ////////////////////////////////////////////////////////////////////
  5538. // Function: NodePath::r_adjust_all_priorities
  5539. // Access: Private
  5540. // Description: The recursive implementation of
  5541. // adjust_all_priorities(). This walks through the
  5542. // subgraph defined by the indicated node and below.
  5543. ////////////////////////////////////////////////////////////////////
  5544. void NodePath::
  5545. r_adjust_all_priorities(PandaNode *node, int adjustment) {
  5546. node->set_state(node->get_state()->adjust_all_priorities(adjustment));
  5547. if (node->is_geom_node()) {
  5548. GeomNode *gnode;
  5549. DCAST_INTO_V(gnode, node);
  5550. int num_geoms = gnode->get_num_geoms();
  5551. for (int i = 0; i < num_geoms; i++) {
  5552. gnode->set_geom_state(i, gnode->get_geom_state(i)->adjust_all_priorities(adjustment));
  5553. }
  5554. }
  5555. PandaNode::Children cr = node->get_children();
  5556. int num_children = cr.get_num_children();
  5557. for (int i = 0; i < num_children; i++) {
  5558. r_adjust_all_priorities(cr.get_child(i), adjustment);
  5559. }
  5560. }
  5561. ////////////////////////////////////////////////////////////////////
  5562. // Function: NodePath::r_force_recompute_bounds
  5563. // Access: Private
  5564. // Description:
  5565. ////////////////////////////////////////////////////////////////////
  5566. void NodePath::
  5567. r_force_recompute_bounds(PandaNode *node) {
  5568. if (node->is_geom_node()) {
  5569. GeomNode *gnode;
  5570. DCAST_INTO_V(gnode, node);
  5571. int num_geoms = gnode->get_num_geoms();
  5572. for (int i = 0; i < num_geoms; i++) {
  5573. const Geom *geom = gnode->get_geom(i);
  5574. geom->mark_bounds_stale();
  5575. }
  5576. }
  5577. node->mark_bounds_stale();
  5578. // Now consider children.
  5579. PandaNode::Children cr = node->get_children();
  5580. int num_children = cr.get_num_children();
  5581. for (int i = 0; i < num_children; i++) {
  5582. r_force_recompute_bounds(cr.get_child(i));
  5583. }
  5584. }
  5585. ////////////////////////////////////////////////////////////////////
  5586. // Function: NodePath::r_set_collide_mask
  5587. // Access: Private
  5588. // Description: Recursively applies the indicated collide mask to the
  5589. // nodes at and below this node.
  5590. ////////////////////////////////////////////////////////////////////
  5591. void NodePath::
  5592. r_set_collide_mask(PandaNode *node,
  5593. CollideMask and_mask, CollideMask or_mask,
  5594. TypeHandle node_type) {
  5595. if (node->is_of_type(node_type)) {
  5596. CollideMask into_collide_mask = node->get_into_collide_mask();
  5597. into_collide_mask = (into_collide_mask & and_mask) | or_mask;
  5598. node->set_into_collide_mask(into_collide_mask);
  5599. }
  5600. PandaNode::Children cr = node->get_children();
  5601. int num_children = cr.get_num_children();
  5602. for (int i = 0; i < num_children; i++) {
  5603. r_set_collide_mask(cr.get_child(i), and_mask, or_mask, node_type);
  5604. }
  5605. }
  5606. ////////////////////////////////////////////////////////////////////
  5607. // Function: NodePath::r_has_vertex_column
  5608. // Access: Private
  5609. // Description:
  5610. ////////////////////////////////////////////////////////////////////
  5611. bool NodePath::
  5612. r_has_vertex_column(PandaNode *node, const InternalName *name) const {
  5613. if (node->is_geom_node()) {
  5614. GeomNode *gnode;
  5615. DCAST_INTO_R(gnode, node, false);
  5616. int num_geoms = gnode->get_num_geoms();
  5617. for (int i = 0; i < num_geoms; i++) {
  5618. const Geom *geom = gnode->get_geom(i);
  5619. CPT(GeomVertexData) vdata = geom->get_vertex_data();
  5620. if (vdata->has_column(name)) {
  5621. return true;
  5622. }
  5623. }
  5624. }
  5625. // Now consider children.
  5626. PandaNode::Children cr = node->get_children();
  5627. int num_children = cr.get_num_children();
  5628. for (int i = 0; i < num_children; i++) {
  5629. PandaNode *child = cr.get_child(i);
  5630. if (r_has_vertex_column(child, name)) {
  5631. return true;
  5632. }
  5633. }
  5634. return false;
  5635. }
  5636. ////////////////////////////////////////////////////////////////////
  5637. // Function: NodePath::r_find_all_vertex_columns
  5638. // Access: Private
  5639. // Description:
  5640. ////////////////////////////////////////////////////////////////////
  5641. void NodePath::
  5642. r_find_all_vertex_columns(PandaNode *node,
  5643. NodePath::InternalNames &vertex_columns) const {
  5644. if (node->is_geom_node()) {
  5645. GeomNode *gnode;
  5646. DCAST_INTO_V(gnode, node);
  5647. int num_geoms = gnode->get_num_geoms();
  5648. for (int i = 0; i < num_geoms; ++i) {
  5649. const Geom *geom = gnode->get_geom(i);
  5650. const GeomVertexFormat *format = geom->get_vertex_data()->get_format();
  5651. int num_arrays = format->get_num_arrays();
  5652. for (int j = 0; j < num_arrays; ++j) {
  5653. const GeomVertexArrayFormat *array = format->get_array(j);
  5654. int num_columns = array->get_num_columns();
  5655. for (int k = 0; k < num_columns; ++k) {
  5656. const GeomVertexColumn *column = array->get_column(k);
  5657. vertex_columns.insert(column->get_name());
  5658. }
  5659. }
  5660. }
  5661. }
  5662. // Now consider children.
  5663. PandaNode::Children cr = node->get_children();
  5664. int num_children = cr.get_num_children();
  5665. for (int i = 0; i < num_children; i++) {
  5666. PandaNode *child = cr.get_child(i);
  5667. r_find_all_vertex_columns(child, vertex_columns);
  5668. }
  5669. }
  5670. ////////////////////////////////////////////////////////////////////
  5671. // Function: NodePath::r_find_texture
  5672. // Access: Private
  5673. // Description:
  5674. ////////////////////////////////////////////////////////////////////
  5675. Texture *NodePath::
  5676. r_find_texture(PandaNode *node, const RenderState *state,
  5677. const GlobPattern &glob) const {
  5678. if (node->is_geom_node()) {
  5679. GeomNode *gnode;
  5680. DCAST_INTO_R(gnode, node, NULL);
  5681. int num_geoms = gnode->get_num_geoms();
  5682. for (int i = 0; i < num_geoms; i++) {
  5683. CPT(RenderState) geom_state =
  5684. state->compose(gnode->get_geom_state(i));
  5685. // Look for a TextureAttrib on the state.
  5686. const RenderAttrib *attrib =
  5687. geom_state->get_attrib(TextureAttrib::get_class_type());
  5688. if (attrib != (const RenderAttrib *)NULL) {
  5689. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5690. for (int i = 0; i < ta->get_num_on_stages(); i++) {
  5691. Texture *texture = ta->get_on_texture(ta->get_on_stage(i));
  5692. if (texture != (Texture *)NULL) {
  5693. if (glob.matches(texture->get_name())) {
  5694. return texture;
  5695. }
  5696. }
  5697. }
  5698. }
  5699. }
  5700. }
  5701. // Now consider children.
  5702. PandaNode::Children cr = node->get_children();
  5703. int num_children = cr.get_num_children();
  5704. for (int i = 0; i < num_children; i++) {
  5705. PandaNode *child = cr.get_child(i);
  5706. CPT(RenderState) next_state = state->compose(child->get_state());
  5707. Texture *result = r_find_texture(child, next_state, glob);
  5708. if (result != (Texture *)NULL) {
  5709. return result;
  5710. }
  5711. }
  5712. return NULL;
  5713. }
  5714. ////////////////////////////////////////////////////////////////////
  5715. // Function: NodePath::r_find_all_textures
  5716. // Access: Private
  5717. // Description:
  5718. ////////////////////////////////////////////////////////////////////
  5719. void NodePath::
  5720. r_find_all_textures(PandaNode *node, const RenderState *state,
  5721. NodePath::Textures &textures) const {
  5722. if (node->is_geom_node()) {
  5723. GeomNode *gnode;
  5724. DCAST_INTO_V(gnode, node);
  5725. int num_geoms = gnode->get_num_geoms();
  5726. for (int i = 0; i < num_geoms; i++) {
  5727. CPT(RenderState) geom_state =
  5728. state->compose(gnode->get_geom_state(i));
  5729. // Look for a TextureAttrib on the state.
  5730. const RenderAttrib *attrib =
  5731. geom_state->get_attrib(TextureAttrib::get_class_type());
  5732. if (attrib != (const RenderAttrib *)NULL) {
  5733. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5734. for (int i = 0; i < ta->get_num_on_stages(); i++) {
  5735. Texture *texture = ta->get_on_texture(ta->get_on_stage(i));
  5736. if (texture != (Texture *)NULL) {
  5737. textures.insert(texture);
  5738. }
  5739. }
  5740. }
  5741. }
  5742. }
  5743. // Now consider children.
  5744. PandaNode::Children cr = node->get_children();
  5745. int num_children = cr.get_num_children();
  5746. for (int i = 0; i < num_children; i++) {
  5747. PandaNode *child = cr.get_child(i);
  5748. CPT(RenderState) next_state = state->compose(child->get_state());
  5749. r_find_all_textures(child, next_state, textures);
  5750. }
  5751. }
  5752. ////////////////////////////////////////////////////////////////////
  5753. // Function: NodePath::r_find_texture
  5754. // Access: Private
  5755. // Description:
  5756. ////////////////////////////////////////////////////////////////////
  5757. Texture * NodePath::
  5758. r_find_texture(PandaNode *node, TextureStage *stage) const {
  5759. // Look for a TextureAttrib on the node.
  5760. const RenderAttrib *attrib =
  5761. node->get_attrib(TextureAttrib::get_class_type());
  5762. if (attrib != (const RenderAttrib *)NULL) {
  5763. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5764. if (ta->has_on_stage(stage)) {
  5765. return ta->get_on_texture(stage);
  5766. }
  5767. }
  5768. if (node->is_geom_node()) {
  5769. GeomNode *gnode;
  5770. DCAST_INTO_R(gnode, node, NULL);
  5771. int num_geoms = gnode->get_num_geoms();
  5772. for (int i = 0; i < num_geoms; i++) {
  5773. CPT(RenderState) geom_state = gnode->get_geom_state(i);
  5774. // Look for a TextureAttrib on the state.
  5775. const RenderAttrib *attrib =
  5776. geom_state->get_attrib(TextureAttrib::get_class_type());
  5777. if (attrib != (const RenderAttrib *)NULL) {
  5778. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5779. if (ta->has_on_stage(stage)) {
  5780. return ta->get_on_texture(stage);
  5781. }
  5782. }
  5783. }
  5784. }
  5785. // Now consider children.
  5786. PandaNode::Children cr = node->get_children();
  5787. int num_children = cr.get_num_children();
  5788. for (int i = 0; i < num_children; i++) {
  5789. PandaNode *child = cr.get_child(i);
  5790. Texture *result = r_find_texture(child, stage);
  5791. if (result != (Texture *)NULL) {
  5792. return result;
  5793. }
  5794. }
  5795. return NULL;
  5796. }
  5797. ////////////////////////////////////////////////////////////////////
  5798. // Function: NodePath::r_find_all_textures
  5799. // Access: Private
  5800. // Description:
  5801. ////////////////////////////////////////////////////////////////////
  5802. void NodePath::
  5803. r_find_all_textures(PandaNode *node, TextureStage *stage,
  5804. NodePath::Textures &textures) const {
  5805. // Look for a TextureAttrib on the node.
  5806. const RenderAttrib *attrib =
  5807. node->get_attrib(TextureAttrib::get_class_type());
  5808. if (attrib != (const RenderAttrib *)NULL) {
  5809. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5810. if (ta->has_on_stage(stage)) {
  5811. textures.insert(ta->get_on_texture(stage));
  5812. }
  5813. }
  5814. if (node->is_geom_node()) {
  5815. GeomNode *gnode;
  5816. DCAST_INTO_V(gnode, node);
  5817. int num_geoms = gnode->get_num_geoms();
  5818. for (int i = 0; i < num_geoms; i++) {
  5819. CPT(RenderState) geom_state = gnode->get_geom_state(i);
  5820. // Look for a TextureAttrib on the state.
  5821. const RenderAttrib *attrib =
  5822. geom_state->get_attrib(TextureAttrib::get_class_type());
  5823. if (attrib != (const RenderAttrib *)NULL) {
  5824. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5825. if (ta->has_on_stage(stage)) {
  5826. textures.insert(ta->get_on_texture(stage));
  5827. }
  5828. }
  5829. }
  5830. }
  5831. // Now consider children.
  5832. PandaNode::Children cr = node->get_children();
  5833. int num_children = cr.get_num_children();
  5834. for (int i = 0; i < num_children; i++) {
  5835. PandaNode *child = cr.get_child(i);
  5836. r_find_all_textures(child, stage, textures);
  5837. }
  5838. }
  5839. ////////////////////////////////////////////////////////////////////
  5840. // Function: NodePath::r_find_texture_stage
  5841. // Access: Private
  5842. // Description:
  5843. ////////////////////////////////////////////////////////////////////
  5844. TextureStage * NodePath::
  5845. r_find_texture_stage(PandaNode *node, const RenderState *state,
  5846. const GlobPattern &glob) const {
  5847. if (node->is_geom_node()) {
  5848. GeomNode *gnode;
  5849. DCAST_INTO_R(gnode, node, NULL);
  5850. int num_geoms = gnode->get_num_geoms();
  5851. for (int i = 0; i < num_geoms; i++) {
  5852. CPT(RenderState) geom_state =
  5853. state->compose(gnode->get_geom_state(i));
  5854. // Look for a TextureAttrib on the state.
  5855. const RenderAttrib *attrib =
  5856. geom_state->get_attrib(TextureAttrib::get_class_type());
  5857. if (attrib != (const RenderAttrib *)NULL) {
  5858. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5859. for (int i = 0; i < ta->get_num_on_stages(); i++) {
  5860. TextureStage *texture_stage = ta->get_on_stage(i);
  5861. if (texture_stage != (TextureStage *)NULL) {
  5862. if (glob.matches(texture_stage->get_name())) {
  5863. return texture_stage;
  5864. }
  5865. }
  5866. }
  5867. }
  5868. }
  5869. }
  5870. // Now consider children.
  5871. PandaNode::Children cr = node->get_children();
  5872. int num_children = cr.get_num_children();
  5873. for (int i = 0; i < num_children; i++) {
  5874. PandaNode *child = cr.get_child(i);
  5875. CPT(RenderState) next_state = state->compose(child->get_state());
  5876. TextureStage *result = r_find_texture_stage(child, next_state, glob);
  5877. if (result != (TextureStage *)NULL) {
  5878. return result;
  5879. }
  5880. }
  5881. return NULL;
  5882. }
  5883. ////////////////////////////////////////////////////////////////////
  5884. // Function: NodePath::r_find_all_texture_stages
  5885. // Access: Private
  5886. // Description:
  5887. ////////////////////////////////////////////////////////////////////
  5888. void NodePath::
  5889. r_find_all_texture_stages(PandaNode *node, const RenderState *state,
  5890. NodePath::TextureStages &texture_stages) const {
  5891. if (node->is_geom_node()) {
  5892. GeomNode *gnode;
  5893. DCAST_INTO_V(gnode, node);
  5894. int num_geoms = gnode->get_num_geoms();
  5895. for (int i = 0; i < num_geoms; i++) {
  5896. CPT(RenderState) geom_state =
  5897. state->compose(gnode->get_geom_state(i));
  5898. // Look for a TextureAttrib on the state.
  5899. const RenderAttrib *attrib =
  5900. geom_state->get_attrib(TextureAttrib::get_class_type());
  5901. if (attrib != (const RenderAttrib *)NULL) {
  5902. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5903. for (int i = 0; i < ta->get_num_on_stages(); i++) {
  5904. TextureStage *texture_stage = ta->get_on_stage(i);
  5905. if (texture_stage != (TextureStage *)NULL) {
  5906. texture_stages.insert(texture_stage);
  5907. }
  5908. }
  5909. }
  5910. }
  5911. }
  5912. // Now consider children.
  5913. PandaNode::Children cr = node->get_children();
  5914. int num_children = cr.get_num_children();
  5915. for (int i = 0; i < num_children; i++) {
  5916. PandaNode *child = cr.get_child(i);
  5917. CPT(RenderState) next_state = state->compose(child->get_state());
  5918. r_find_all_texture_stages(child, next_state, texture_stages);
  5919. }
  5920. }
  5921. ////////////////////////////////////////////////////////////////////
  5922. // Function: NodePath::r_unify_texture_stages
  5923. // Access: Private
  5924. // Description:
  5925. ////////////////////////////////////////////////////////////////////
  5926. void NodePath::
  5927. r_unify_texture_stages(PandaNode *node, TextureStage *stage) {
  5928. // Look for a TextureAttrib on the state.
  5929. const RenderAttrib *attrib =
  5930. node->get_attrib(TextureAttrib::get_class_type());
  5931. if (attrib != (const RenderAttrib *)NULL) {
  5932. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5933. CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage);
  5934. if (new_attrib != ta) {
  5935. node->set_attrib(new_attrib);
  5936. }
  5937. }
  5938. if (node->is_geom_node()) {
  5939. GeomNode *gnode;
  5940. DCAST_INTO_V(gnode, node);
  5941. int num_geoms = gnode->get_num_geoms();
  5942. for (int i = 0; i < num_geoms; i++) {
  5943. CPT(RenderState) state = gnode->get_geom_state(i);
  5944. // Look for a TextureAttrib on the state.
  5945. const RenderAttrib *attrib =
  5946. state->get_attrib(TextureAttrib::get_class_type());
  5947. if (attrib != (const RenderAttrib *)NULL) {
  5948. const TextureAttrib *ta = DCAST(TextureAttrib, attrib);
  5949. CPT(RenderAttrib) new_attrib = ta->unify_texture_stages(stage);
  5950. if (new_attrib != ta) {
  5951. CPT(RenderState) new_state = state->add_attrib(new_attrib);
  5952. gnode->set_geom_state(i, new_state);
  5953. }
  5954. }
  5955. }
  5956. }
  5957. // Now consider children.
  5958. PandaNode::Children cr = node->get_children();
  5959. int num_children = cr.get_num_children();
  5960. for (int i = 0; i < num_children; i++) {
  5961. PandaNode *child = cr.get_child(i);
  5962. r_unify_texture_stages(child, stage);
  5963. }
  5964. }
  5965. ////////////////////////////////////////////////////////////////////
  5966. // Function: NodePath::r_find_material
  5967. // Access: Private
  5968. // Description:
  5969. ////////////////////////////////////////////////////////////////////
  5970. Material *NodePath::
  5971. r_find_material(PandaNode *node, const RenderState *state,
  5972. const GlobPattern &glob) const {
  5973. if (node->is_geom_node()) {
  5974. GeomNode *gnode;
  5975. DCAST_INTO_R(gnode, node, NULL);
  5976. int num_geoms = gnode->get_num_geoms();
  5977. for (int i = 0; i < num_geoms; i++) {
  5978. CPT(RenderState) geom_state =
  5979. state->compose(gnode->get_geom_state(i));
  5980. // Look for a MaterialAttrib on the state.
  5981. const RenderAttrib *attrib =
  5982. geom_state->get_attrib(MaterialAttrib::get_class_type());
  5983. if (attrib != (const RenderAttrib *)NULL) {
  5984. const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib);
  5985. if (!ta->is_off()) {
  5986. Material *material = ta->get_material();
  5987. if (material != (Material *)NULL) {
  5988. return material;
  5989. }
  5990. }
  5991. }
  5992. }
  5993. }
  5994. // Now consider children.
  5995. PandaNode::Children cr = node->get_children();
  5996. int num_children = cr.get_num_children();
  5997. for (int i = 0; i < num_children; i++) {
  5998. PandaNode *child = cr.get_child(i);
  5999. CPT(RenderState) next_state = state->compose(child->get_state());
  6000. Material *result = r_find_material(child, next_state, glob);
  6001. if (result != (Material *)NULL) {
  6002. return result;
  6003. }
  6004. }
  6005. return NULL;
  6006. }
  6007. ////////////////////////////////////////////////////////////////////
  6008. // Function: NodePath::r_find_all_materials
  6009. // Access: Private
  6010. // Description:
  6011. ////////////////////////////////////////////////////////////////////
  6012. void NodePath::
  6013. r_find_all_materials(PandaNode *node, const RenderState *state,
  6014. NodePath::Materials &materials) const {
  6015. if (node->is_geom_node()) {
  6016. GeomNode *gnode;
  6017. DCAST_INTO_V(gnode, node);
  6018. int num_geoms = gnode->get_num_geoms();
  6019. for (int i = 0; i < num_geoms; i++) {
  6020. CPT(RenderState) geom_state =
  6021. state->compose(gnode->get_geom_state(i));
  6022. // Look for a MaterialAttrib on the state.
  6023. const RenderAttrib *attrib =
  6024. geom_state->get_attrib(MaterialAttrib::get_class_type());
  6025. if (attrib != (const RenderAttrib *)NULL) {
  6026. const MaterialAttrib *ta = DCAST(MaterialAttrib, attrib);
  6027. if (!ta->is_off()) {
  6028. Material *material = ta->get_material();
  6029. if (material != (Material *)NULL) {
  6030. materials.insert(material);
  6031. }
  6032. }
  6033. }
  6034. }
  6035. }
  6036. // Now consider children.
  6037. PandaNode::Children cr = node->get_children();
  6038. int num_children = cr.get_num_children();
  6039. for (int i = 0; i < num_children; i++) {
  6040. PandaNode *child = cr.get_child(i);
  6041. CPT(RenderState) next_state = state->compose(child->get_state());
  6042. r_find_all_materials(child, next_state, materials);
  6043. }
  6044. }
  6045. ////////////////////////////////////////////////////////////////////
  6046. // Function: NodePath::r_prepare_scene
  6047. // Access: Private
  6048. // Description: The recursive implementation of prepare_scene.
  6049. ////////////////////////////////////////////////////////////////////
  6050. void NodePath::
  6051. r_prepare_scene(PandaNode *node, const RenderState *state,
  6052. PreparedGraphicsObjects *prepared_objects) {
  6053. if (node->is_geom_node()) {
  6054. GeomNode *gnode;
  6055. DCAST_INTO_V(gnode, node);
  6056. /*
  6057. Not implemented yet in pgraph. Maybe we don't need this anyway.
  6058. if (retained_mode) {
  6059. gnode->prepare(gsg);
  6060. }
  6061. */
  6062. int num_geoms = gnode->get_num_geoms();
  6063. for (int i = 0; i < num_geoms; i++) {
  6064. CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i));
  6065. const RenderAttrib *attrib =
  6066. geom_state->get_attrib(TextureAttrib::get_class_type());
  6067. if (attrib != (const RenderAttrib *)NULL) {
  6068. const TextureAttrib *ta;
  6069. DCAST_INTO_V(ta, attrib);
  6070. Texture *texture = ta->get_texture();
  6071. if (texture != (Texture *)NULL) {
  6072. texture->prepare(prepared_objects);
  6073. }
  6074. }
  6075. }
  6076. }
  6077. int num_children = node->get_num_children();
  6078. for (int i = 0; i < num_children; i++) {
  6079. PandaNode *child = node->get_child(i);
  6080. CPT(RenderState) child_state = state->compose(child->get_state());
  6081. r_prepare_scene(child, child_state, prepared_objects);
  6082. }
  6083. }