| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619 |
- // Filename: glGraphicsStateGuardian_src.cxx
- // Created by: drose (02Feb99)
- // Updated by: fperazzi, PandaSE (05May10) (added
- // get_supports_cg_profile)
- //
- ////////////////////////////////////////////////////////////////////
- //
- // PANDA 3D SOFTWARE
- // Copyright (c) Carnegie Mellon University. All rights reserved.
- //
- // All use of this software is subject to the terms of the revised BSD
- // license. You should have received a copy of this license along
- // with this source code in a file named "LICENSE."
- //
- ////////////////////////////////////////////////////////////////////
- #include "config_util.h"
- #include "displayRegion.h"
- #include "renderBuffer.h"
- #include "geom.h"
- #include "geomVertexData.h"
- #include "geomTriangles.h"
- #include "geomTristrips.h"
- #include "geomTrifans.h"
- #include "geomLines.h"
- #include "geomLinestrips.h"
- #include "geomPoints.h"
- #include "geomVertexReader.h"
- #include "graphicsWindow.h"
- #include "lens.h"
- #include "perspectiveLens.h"
- #include "directionalLight.h"
- #include "pointLight.h"
- #include "spotlight.h"
- #include "planeNode.h"
- #include "fog.h"
- #include "clockObject.h"
- #include "string_utils.h"
- #include "nodePath.h"
- #include "dcast.h"
- #include "pvector.h"
- #include "vector_string.h"
- #include "string_utils.h"
- #include "pnmImage.h"
- #include "config_gobj.h"
- #include "lightMutexHolder.h"
- #include "indirectLess.h"
- #include "pStatTimer.h"
- #include "load_prc_file.h"
- #include "bamCache.h"
- #include "bamCacheRecord.h"
- #include "alphaTestAttrib.h"
- #include "clipPlaneAttrib.h"
- #include "cullFaceAttrib.h"
- #include "depthOffsetAttrib.h"
- #include "depthWriteAttrib.h"
- #include "fogAttrib.h"
- #include "lightAttrib.h"
- #include "materialAttrib.h"
- #include "rescaleNormalAttrib.h"
- #include "scissorAttrib.h"
- #include "shadeModelAttrib.h"
- #include "stencilAttrib.h"
- #include "graphicsEngine.h"
- #include "shaderGenerator.h"
- #include "samplerState.h"
- #include "displayInformation.h"
- #if defined(HAVE_CG) && !defined(OPENGLES)
- #include "Cg/cgGL.h"
- #endif
- #include <algorithm>
- TypeHandle CLP(GraphicsStateGuardian)::_type_handle;
- PStatCollector CLP(GraphicsStateGuardian)::_load_display_list_pcollector("Draw:Transfer data:Display lists");
- PStatCollector CLP(GraphicsStateGuardian)::_primitive_batches_display_list_pcollector("Primitive batches:Display lists");
- PStatCollector CLP(GraphicsStateGuardian)::_vertices_display_list_pcollector("Vertices:Display lists");
- PStatCollector CLP(GraphicsStateGuardian)::_vertices_immediate_pcollector("Vertices:Immediate mode");
- PStatCollector CLP(GraphicsStateGuardian)::_memory_barrier_pcollector("Draw:Memory barriers");
- PStatCollector CLP(GraphicsStateGuardian)::_vertex_array_update_pcollector("Draw:Update arrays");
- PStatCollector CLP(GraphicsStateGuardian)::_texture_update_pcollector("Draw:Update texture");
- PStatCollector CLP(GraphicsStateGuardian)::_fbo_bind_pcollector("Draw:Bind FBO");
- PStatCollector CLP(GraphicsStateGuardian)::_check_error_pcollector("Draw:Check errors");
- #ifndef OPENGLES_1
- PT(Shader) CLP(GraphicsStateGuardian)::_default_shader = NULL;
- #endif
- // The following noop functions are assigned to the corresponding
- // glext function pointers in the class, in case the functions are not
- // defined by the GL, just so it will always be safe to call the
- // extension functions.
- static void APIENTRY
- null_glPointParameterfv(GLenum, const GLfloat *) {
- }
- #ifdef OPENGLES
- // OpenGL ES doesn't support this, period. Might as well macro it.
- #define _glDrawRangeElements(mode, start, end, count, type, indices) \
- glDrawElements(mode, count, type, indices)
- #else
- static void APIENTRY
- null_glDrawRangeElements(GLenum mode, GLuint start, GLuint end,
- GLsizei count, GLenum type, const GLvoid *indices) {
- // If we don't support glDrawRangeElements(), just use the original
- // glDrawElements() instead.
- glDrawElements(mode, count, type, indices);
- }
- #endif
- static void APIENTRY
- null_glActiveTexture(GLenum gl_texture_stage) {
- // If we don't support multitexture, we'd better not try to request
- // a texture beyond the first texture stage.
- nassertv(gl_texture_stage == GL_TEXTURE0);
- }
- static void APIENTRY
- null_glBlendEquation(GLenum) {
- }
- static void APIENTRY
- null_glBlendColor(GLclampf, GLclampf, GLclampf, GLclampf) {
- }
- #ifndef OPENGLES_1
- // We have a default shader that will be applied when there isn't any
- // shader applied (e.g. if it failed to compile). We need this because
- // OpenGL ES 2.x and OpenGL 3.2+ core don't have a fixed-function pipeline.
- // This default shader just applies a single texture, which is good enough
- // for drawing GUIs and such.
- static const string default_vshader =
- #ifndef OPENGLES
- "#version 130\n"
- "in vec4 p3d_Vertex;\n"
- "in vec4 p3d_Color;\n"
- "in vec2 p3d_MultiTexCoord0;\n"
- "out vec2 texcoord;\n"
- "out vec4 color;\n"
- #else
- "precision mediump float;\n"
- "attribute vec4 p3d_Vertex;\n"
- "attribute vec4 p3d_Color;\n"
- "attribute vec2 p3d_MultiTexCoord0;\n"
- "varying vec2 texcoord;\n"
- "varying vec4 color;\n"
- #endif
- "uniform mat4 p3d_ModelViewProjectionMatrix;\n"
- "uniform vec4 p3d_ColorScale;\n"
- "void main(void) {\n"
- " gl_Position = p3d_ModelViewProjectionMatrix * p3d_Vertex;\n"
- " texcoord = p3d_MultiTexCoord0;\n"
- " color = p3d_Color * p3d_ColorScale;\n"
- "}\n";
- static const string default_fshader =
- #ifndef OPENGLES
- "#version 130\n"
- "in vec2 texcoord;\n"
- "in vec4 color;\n"
- #else
- "precision mediump float;\n"
- "varying vec2 texcoord;\n"
- "varying vec4 color;\n"
- #endif
- "uniform sampler2D p3d_Texture0;\n"
- "void main(void) {\n"
- #ifndef OPENGLES
- " gl_FragColor = texture(p3d_Texture0, texcoord);\n"
- #else
- " gl_FragColor = texture2D(p3d_Texture0, texcoord).bgra;\n"
- #endif
- " gl_FragColor *= color;\n"
- "}\n";
- #endif
- ////////////////////////////////////////////////////////////////////
- // Function: uchar_bgr_to_rgb
- // Description: Recopies the given array of pixels, converting from
- // BGR to RGB arrangement.
- ////////////////////////////////////////////////////////////////////
- static void
- uchar_bgr_to_rgb(unsigned char *dest, const unsigned char *source,
- int num_pixels) {
- for (int i = 0; i < num_pixels; i++) {
- dest[0] = source[2];
- dest[1] = source[1];
- dest[2] = source[0];
- dest += 3;
- source += 3;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: uchar_bgra_to_rgba
- // Description: Recopies the given array of pixels, converting from
- // BGRA to RGBA arrangement.
- ////////////////////////////////////////////////////////////////////
- static void
- uchar_bgra_to_rgba(unsigned char *dest, const unsigned char *source,
- int num_pixels) {
- for (int i = 0; i < num_pixels; i++) {
- dest[0] = source[2];
- dest[1] = source[1];
- dest[2] = source[0];
- dest[3] = source[3];
- dest += 4;
- source += 4;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: ushort_bgr_to_rgb
- // Description: Recopies the given array of pixels, converting from
- // BGR to RGB arrangement.
- ////////////////////////////////////////////////////////////////////
- static void
- ushort_bgr_to_rgb(unsigned short *dest, const unsigned short *source,
- int num_pixels) {
- for (int i = 0; i < num_pixels; i++) {
- dest[0] = source[2];
- dest[1] = source[1];
- dest[2] = source[0];
- dest += 3;
- source += 3;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: ushort_bgra_to_rgba
- // Description: Recopies the given array of pixels, converting from
- // BGRA to RGBA arrangement.
- ////////////////////////////////////////////////////////////////////
- static void
- ushort_bgra_to_rgba(unsigned short *dest, const unsigned short *source,
- int num_pixels) {
- for (int i = 0; i < num_pixels; i++) {
- dest[0] = source[2];
- dest[1] = source[1];
- dest[2] = source[0];
- dest[3] = source[3];
- dest += 4;
- source += 4;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: fix_component_ordering
- // Description: Reverses the order of the components within the
- // image, to convert (for instance) GL_BGR to GL_RGB.
- // Returns the byte pointer representing the converted
- // image, or the original image if it is unchanged.
- //
- // new_image must be supplied; it is the PTA_uchar that
- // will be used to hold the converted image if required.
- // It will be modified only if the conversion is
- // necessary, in which case the data will be stored
- // there, and this pointer will be returned. If the
- // conversion is not necessary, this pointer will be
- // left unchanged.
- ////////////////////////////////////////////////////////////////////
- static const unsigned char *
- fix_component_ordering(PTA_uchar &new_image,
- const unsigned char *orig_image, size_t orig_image_size,
- GLenum external_format, Texture *tex) {
- const unsigned char *result = orig_image;
- switch (external_format) {
- case GL_RGB:
- switch (tex->get_component_type()) {
- case Texture::T_unsigned_byte:
- new_image = PTA_uchar::empty_array(orig_image_size);
- uchar_bgr_to_rgb(new_image, orig_image, orig_image_size / 3);
- result = new_image;
- break;
- case Texture::T_unsigned_short:
- new_image = PTA_uchar::empty_array(orig_image_size);
- ushort_bgr_to_rgb((unsigned short *)new_image.p(),
- (const unsigned short *)orig_image,
- orig_image_size / 6);
- result = new_image;
- break;
- default:
- break;
- }
- break;
- case GL_RGBA:
- switch (tex->get_component_type()) {
- case Texture::T_unsigned_byte:
- new_image = PTA_uchar::empty_array(orig_image_size);
- uchar_bgra_to_rgba(new_image, orig_image, orig_image_size / 4);
- result = new_image;
- break;
- case Texture::T_unsigned_short:
- new_image = PTA_uchar::empty_array(orig_image_size);
- ushort_bgra_to_rgba((unsigned short *)new_image.p(),
- (const unsigned short *)orig_image,
- orig_image_size / 8);
- result = new_image;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- return result;
- }
- //#--- Zhao Nov/2011
- string CLP(GraphicsStateGuardian)::get_driver_vendor() { return _gl_vendor; }
- string CLP(GraphicsStateGuardian)::get_driver_renderer() { return _gl_renderer; }
- string CLP(GraphicsStateGuardian)::get_driver_version() { return _gl_version; }
- int CLP(GraphicsStateGuardian)::get_driver_version_major() { return _gl_version_major; }
- int CLP(GraphicsStateGuardian)::get_driver_version_minor() { return _gl_version_minor; }
- int CLP(GraphicsStateGuardian)::get_driver_shader_version_major() { return _gl_shadlang_ver_major; }
- int CLP(GraphicsStateGuardian)::get_driver_shader_version_minor() { return _gl_shadlang_ver_minor; }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::Constructor
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- CLP(GraphicsStateGuardian)::
- CLP(GraphicsStateGuardian)(GraphicsEngine *engine, GraphicsPipe *pipe) :
- GraphicsStateGuardian(gl_coordinate_system, engine, pipe),
- _renderbuffer_residency(get_prepared_objects()->get_name(), "renderbuffer")
- {
- _error_count = 0;
- _gl_shadlang_ver_major = 0;
- _gl_shadlang_ver_minor = 0;
- // Hack. Turn on the flag that we turned off at a higher level,
- // since we know this works properly in OpenGL, and we want the
- // performance benefit it gives us.
- _prepared_objects->_support_released_buffer_cache = true;
- // Assume that we will get a hardware-accelerated context, unless
- // the window tells us otherwise.
- _is_hardware = true;
- // calling glGetError() forces a sync, this turns it on if you want to.
- _check_errors = gl_check_errors;
- _force_flush = gl_force_flush;
- _scissor_enabled = false;
- _scissor_attrib_active = false;
- _white_texture = 0;
- #ifdef HAVE_CG
- _cg_context = 0;
- #endif
- #ifdef DO_PSTATS
- if (gl_finish) {
- GLCAT.warning()
- << "The config variable gl-finish is set to true. This may have a substantial negative impact on your render performance.\n";
- }
- #endif // DO_PSTATS
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::Destructor
- // Access: Public
- // Description:
- ////////////////////////////////////////////////////////////////////
- CLP(GraphicsStateGuardian)::
- ~CLP(GraphicsStateGuardian)() {
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "GLGraphicsStateGuardian " << this << " destructing\n";
- }
- close_gsg();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::debug_callback
- // Access: Public, Static
- // Description: This is called by the GL if an error occurs, if
- // gl_debug has been enabled (and the driver supports
- // the GL_ARB_debug_output extension).
- ////////////////////////////////////////////////////////////////////
- #ifndef OPENGLES_1
- void CLP(GraphicsStateGuardian)::
- debug_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, GLvoid *userParam) {
- // Determine how to map the severity level.
- NotifySeverity level;
- switch (severity) {
- case GL_DEBUG_SEVERITY_HIGH:
- level = NS_error;
- break;
- case GL_DEBUG_SEVERITY_MEDIUM:
- level = NS_warning;
- break;
- case GL_DEBUG_SEVERITY_LOW:
- level = NS_info;
- break;
- case GL_DEBUG_SEVERITY_NOTIFICATION:
- level = NS_debug;
- break;
- default:
- level = NS_fatal; //???
- break;
- }
- string msg_str(message, length);
- GLCAT.out(level) << msg_str << "\n";
- #ifndef NDEBUG
- if (level >= gl_debug_abort_level.get_value()) {
- abort();
- }
- #endif
- }
- #endif // OPENGLES_1
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::reset
- // Access: Public, Virtual
- // Description: Resets all internal state as if the gsg were newly
- // created.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- reset() {
- free_pointers();
- GraphicsStateGuardian::reset();
- // Build _inv_state_mask as a mask of 1's where we don't care, and
- // 0's where we do care, about the state.
- //_inv_state_mask = RenderState::SlotMask::all_on();
- _inv_state_mask.clear_bit(ShaderAttrib::get_class_slot());
- _inv_state_mask.clear_bit(AlphaTestAttrib::get_class_slot());
- _inv_state_mask.clear_bit(AntialiasAttrib::get_class_slot());
- _inv_state_mask.clear_bit(ClipPlaneAttrib::get_class_slot());
- _inv_state_mask.clear_bit(ColorAttrib::get_class_slot());
- _inv_state_mask.clear_bit(ColorScaleAttrib::get_class_slot());
- _inv_state_mask.clear_bit(CullFaceAttrib::get_class_slot());
- _inv_state_mask.clear_bit(DepthOffsetAttrib::get_class_slot());
- _inv_state_mask.clear_bit(DepthTestAttrib::get_class_slot());
- _inv_state_mask.clear_bit(DepthWriteAttrib::get_class_slot());
- _inv_state_mask.clear_bit(RenderModeAttrib::get_class_slot());
- _inv_state_mask.clear_bit(RescaleNormalAttrib::get_class_slot());
- _inv_state_mask.clear_bit(ShadeModelAttrib::get_class_slot());
- _inv_state_mask.clear_bit(TransparencyAttrib::get_class_slot());
- _inv_state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
- _inv_state_mask.clear_bit(ColorBlendAttrib::get_class_slot());
- _inv_state_mask.clear_bit(TextureAttrib::get_class_slot());
- _inv_state_mask.clear_bit(TexGenAttrib::get_class_slot());
- _inv_state_mask.clear_bit(TexMatrixAttrib::get_class_slot());
- _inv_state_mask.clear_bit(MaterialAttrib::get_class_slot());
- _inv_state_mask.clear_bit(LightAttrib::get_class_slot());
- _inv_state_mask.clear_bit(StencilAttrib::get_class_slot());
- _inv_state_mask.clear_bit(FogAttrib::get_class_slot());
- _inv_state_mask.clear_bit(ScissorAttrib::get_class_slot());
- // Output the vendor and version strings.
- query_gl_version();
- if (_gl_version_major == 0) {
- // Couldn't get GL. Fail.
- mark_new();
- return;
- }
- // Save the extensions tokens.
- _extensions.clear();
- // In OpenGL 3.0 and later, glGetString(GL_EXTENSIONS) is deprecated.
- #ifndef OPENGLES
- if (is_at_least_gl_version(3, 0)) {
- PFNGLGETSTRINGIPROC _glGetStringi =
- (PFNGLGETSTRINGIPROC)get_extension_func("glGetStringi");
- if (_glGetStringi != NULL) {
- GLint n = 0;
- glGetIntegerv(GL_NUM_EXTENSIONS, &n);
- for (GLint i = 0; i < n; ++i) {
- const char *extension = (const char *)_glGetStringi(GL_EXTENSIONS, i);
- _extensions.insert(string(extension));
- }
- } else {
- GLCAT.error() << "glGetStringi is not available!\n";
- save_extensions((const char *)glGetString(GL_EXTENSIONS));
- }
- } else
- #endif
- {
- save_extensions((const char *)glGetString(GL_EXTENSIONS));
- }
- get_extra_extensions();
- // This needs access to the extensions, so put this after save_extensions.
- query_glsl_version();
- #ifndef OPENGLES
- bool core_profile;
- if (_gl_version_major < 3 || has_extension("GL_ARB_compatibility")) {
- core_profile = false;
- } else {
- core_profile = true;
- }
- if (core_profile) {
- GLCAT.debug() << "Using core profile\n";
- } else {
- GLCAT.debug() << "Using compatibility profile\n";
- }
- #elif defined(OPENGLES_1)
- static const bool core_profile = false;
- #else
- static const bool core_profile = true;
- #endif
- // Print out a list of all extensions.
- report_extensions();
- // Initialize OpenGL debugging output first, if enabled and supported.
- _supports_debug = false;
- _use_object_labels = false;
- #ifndef OPENGLES_1
- if (gl_debug) {
- PFNGLDEBUGMESSAGECALLBACKPROC _glDebugMessageCallback;
- PFNGLDEBUGMESSAGECONTROLPROC _glDebugMessageControl;
- if (is_at_least_gl_version(4, 3) || has_extension("GL_KHR_debug")) {
- #ifdef OPENGLES
- _glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)
- get_extension_func("glDebugMessageCallbackKHR");
- _glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)
- get_extension_func("glDebugMessageControlKHR");
- _glObjectLabel = (PFNGLOBJECTLABELPROC)
- get_extension_func("glObjectLabelKHR");
- #else
- _glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)
- get_extension_func("glDebugMessageCallback");
- _glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)
- get_extension_func("glDebugMessageControl");
- _glObjectLabel = (PFNGLOBJECTLABELPROC)
- get_extension_func("glObjectLabel");
- #endif
- glEnable(GL_DEBUG_OUTPUT); // Not supported in ARB version
- _supports_debug = true;
- _use_object_labels = gl_debug_object_labels;
- #ifndef OPENGLES
- } else if (has_extension("GL_ARB_debug_output")) {
- _glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC)
- get_extension_func("glDebugMessageCallbackARB");
- _glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC)
- get_extension_func("glDebugMessageControlARB");
- _supports_debug = true;
- #endif
- }
- if (_supports_debug) {
- // Set the categories we want to listen to.
- _glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_HIGH,
- 0, NULL, GLCAT.is_error());
- _glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_MEDIUM,
- 0, NULL, GLCAT.is_warning());
- _glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_LOW,
- 0, NULL, GLCAT.is_info());
- _glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION,
- 0, NULL, GLCAT.is_debug());
- // Enable the callback.
- _glDebugMessageCallback((GLDEBUGPROC) &debug_callback, (void*)this);
- if (gl_debug_synchronous) {
- glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
- }
- GLCAT.debug() << "gl-debug enabled.\n";
- } else {
- GLCAT.debug() << "gl-debug enabled, but NOT supported.\n";
- }
- } else {
- GLCAT.debug() << "gl-debug NOT enabled.\n";
- // However, still check if it is supported.
- _supports_debug = is_at_least_gl_version(4, 3)
- || has_extension("GL_KHR_debug")
- || has_extension("GL_ARB_debug_output");
- }
- #endif // OPENGLES_1
- _supported_geom_rendering =
- Geom::GR_indexed_point |
- Geom::GR_point | Geom::GR_point_uniform_size |
- Geom::GR_indexed_other |
- Geom::GR_triangle_strip | Geom::GR_triangle_fan |
- Geom::GR_line_strip |
- Geom::GR_flat_last_vertex;
- _supports_point_parameters = false;
- #ifndef OPENGLES_2
- if (is_at_least_gl_version(1, 4)) {
- _supports_point_parameters = true;
- _glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)
- get_extension_func("glPointParameterfv");
- } else if (has_extension("GL_ARB_point_parameters")) {
- _supports_point_parameters = true;
- _glPointParameterfv = (PFNGLPOINTPARAMETERFVPROC)
- get_extension_func("glPointParameterfvARB");
- }
- if (_supports_point_parameters) {
- if (_glPointParameterfv == NULL) {
- GLCAT.warning()
- << "glPointParameterfv advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _supports_point_parameters = false;
- }
- }
- if (_supports_point_parameters) {
- _supported_geom_rendering |= Geom::GR_point_perspective | Geom::GR_point_scale;
- } else {
- _glPointParameterfv = null_glPointParameterfv;
- }
- #endif // !OPENGLES_2
- #if defined(OPENGLES_2)
- // OpenGL ES 2 doesn't have point sprites.
- _supports_point_sprite = false;
- #elif defined(OPENGLES_1)
- _supports_point_sprite = has_extension("GL_OES_point_sprite");
- #else
- _supports_point_sprite = has_extension("GL_ARB_point_sprite");
- #endif
- if (_supports_point_sprite) {
- // It appears that the point_sprite extension doesn't support
- // texture transforms on the generated texture coordinates. How
- // inconsistent. Because of this, we don't advertise
- // GR_point_sprite_tex_matrix.
- _supported_geom_rendering |= Geom::GR_point_sprite;
- }
- #ifndef OPENGLES
- _explicit_primitive_restart = false;
- _glPrimitiveRestartIndex = NULL;
- if (gl_support_primitive_restart_index) {
- if ((is_at_least_gl_version(4, 3) || has_extension("GL_ARB_ES3_compatibility")) &&
- _gl_renderer.substr(0, 7) != "Gallium") {
- // As long as we enable this, OpenGL will always use the highest possible index
- // for a numeric type as strip cut index, which coincides with our convention.
- // This saves us a call to glPrimitiveRestartIndex
- // ... of course, though, the Gallium driver bugs out here. See also:
- // https://www.panda3d.org/forums/viewtopic.php?f=5&t=17512
- glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX);
- _supported_geom_rendering |= Geom::GR_strip_cut_index;
- } else if (is_at_least_gl_version(3, 1)) {
- // We have to use an explicit primitive restart enable/index.
- _explicit_primitive_restart = true;
- _supported_geom_rendering |= Geom::GR_strip_cut_index;
- _glPrimitiveRestartIndex = (PFNGLPRIMITIVERESTARTINDEXPROC)
- get_extension_func("glPrimitiveRestartIndex");
- }
- }
- #endif
- #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION)
- if (is_at_least_gl_version(1, 4)) {
- _glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)
- get_extension_func("glSecondaryColorPointer");
- } else if (has_extension("GL_EXT_secondary_color")) {
- _glSecondaryColorPointer = (PFNGLSECONDARYCOLORPOINTERPROC)
- get_extension_func("glSecondaryColorPointerEXT");
- }
- #endif
- #ifndef OPENGLES
- _glDrawRangeElements = null_glDrawRangeElements;
- if (is_at_least_gl_version(1, 2)) {
- _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)
- get_extension_func("glDrawRangeElements");
- } else if (has_extension("GL_EXT_draw_range_elements")) {
- _glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC)
- get_extension_func("glDrawRangeElementsEXT");
- }
- if (_glDrawRangeElements == NULL) {
- GLCAT.warning()
- << "glDrawRangeElements advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _glDrawRangeElements = null_glDrawRangeElements;
- }
- #endif
- _supports_3d_texture = false;
- #ifndef OPENGLES_1
- if (is_at_least_gl_version(1, 2)) {
- _supports_3d_texture = true;
- _glTexImage3D = (PFNGLTEXIMAGE3DPROC_P)
- get_extension_func("glTexImage3D");
- _glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)
- get_extension_func("glTexSubImage3D");
- _glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)
- get_extension_func("glCopyTexSubImage3D");
- } else if (has_extension("GL_EXT_texture3D")) {
- _supports_3d_texture = true;
- _glTexImage3D = (PFNGLTEXIMAGE3DPROC_P)
- get_extension_func("glTexImage3DEXT");
- _glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)
- get_extension_func("glTexSubImage3DEXT");
- _glCopyTexSubImage3D = NULL;
- if (has_extension("GL_EXT_copy_texture")) {
- _glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)
- get_extension_func("glCopyTexSubImage3DEXT");
- }
- } else if (has_extension("GL_OES_texture_3D")) {
- _supports_3d_texture = true;
- _glTexImage3D = (PFNGLTEXIMAGE3DPROC_P)
- get_extension_func("glTexImage3DOES");
- _glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC)
- get_extension_func("glTexSubImage3DOES");
- _glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC)
- get_extension_func("glCopyTexSubImage3DOES");
- #ifdef OPENGLES_2
- _glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DOES)
- get_extension_func("glFramebufferTexture3DOES");
- #endif
- }
- if (_supports_3d_texture) {
- if (_glTexImage3D == NULL || _glTexSubImage3D == NULL) {
- GLCAT.warning()
- << "3-D textures advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _supports_3d_texture = false;
- }
- }
- #endif // !OPENGLES_1
- _supports_tex_storage = false;
- #ifndef OPENGLES
- if (is_at_least_gl_version(4, 2) || has_extension("GL_ARB_texture_storage")) {
- _supports_tex_storage = true;
- _glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)
- get_extension_func("glTexStorage1D");
- _glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)
- get_extension_func("glTexStorage2D");
- _glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)
- get_extension_func("glTexStorage3D");
- } else
- #endif
- if (has_extension("GL_EXT_texture_storage")) { // GLES case
- _supports_tex_storage = true;
- _glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)
- get_extension_func("glTexStorage1DEXT");
- _glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)
- get_extension_func("glTexStorage2DEXT");
- _glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)
- get_extension_func("glTexStorage3DEXT");
- }
- if (_supports_tex_storage) {
- if (_glTexStorage1D == NULL || _glTexStorage2D == NULL || _glTexStorage3D == NULL) {
- GLCAT.warning()
- << "Immutable texture storage advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _supports_tex_storage = false;
- }
- }
- _supports_clear_texture = false;
- #ifndef OPENGLES
- if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_clear_texture")) {
- _glClearTexImage = (PFNGLCLEARTEXIMAGEPROC)
- get_extension_func("glClearTexImage");
- if (_glClearTexImage == NULL) {
- GLCAT.warning()
- << "GL_ARB_clear_texture advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- } else {
- _supports_clear_texture = true;
- }
- }
- #endif
- _supports_2d_texture_array = false;
- #ifndef OPENGLES
- if (is_at_least_gl_version(3, 0)) {
- _supports_2d_texture_array = true;
- _glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)
- get_extension_func("glFramebufferTextureLayer");
- } else if (has_extension("GL_EXT_texture_array")) {
- _supports_2d_texture_array = true;
- _glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC)
- get_extension_func("glFramebufferTextureLayerEXT");
- }
- if (_supports_2d_texture_array && _glFramebufferTextureLayer == NULL) {
- GLCAT.warning()
- << "Texture arrays advertised as supported by OpenGL runtime, but could not get pointer to glFramebufferTextureLayer function.\n";
- }
- #endif
- #ifdef OPENGLES_2
- _supports_cube_map = true;
- #else
- _supports_cube_map =
- has_extension("GL_ARB_texture_cube_map") || is_at_least_gl_version(1, 3) ||
- has_extension("GL_OES_texture_cube_map");
- #endif
- #ifndef OPENGLES
- if (_supports_cube_map && gl_cube_map_seamless) {
- if (is_at_least_gl_version(3, 2) || has_extension("GL_ARB_seamless_cube_map")) {
- glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
- }
- }
- #endif
- #ifndef OPENGLES
- if (is_at_least_gl_version(3, 0)) {
- _glTexBuffer = (PFNGLTEXBUFFERPROC)get_extension_func("glTexBuffer");
- _supports_buffer_texture = true;
- } else if (has_extension("GL_ARB_texture_buffer_object")) {
- _glTexBuffer = (PFNGLTEXBUFFERPROC)get_extension_func("glTexBufferARB");
- _supports_buffer_texture = true;
- }
- #endif
- _supports_texture_srgb = false;
- if (is_at_least_gl_version(2, 1) || has_extension("GL_EXT_texture_sRGB")) {
- _supports_texture_srgb = true;
- } else if (has_extension("GL_EXT_sRGB")) { // GLES case.
- _supports_texture_srgb = true;
- }
- _supports_compressed_texture = false;
- #ifdef OPENGLES
- _supports_compressed_texture = true;
- // Supported in the core. 1D textures are not supported by OpenGL ES.
- _glCompressedTexImage1D = NULL;
- _glCompressedTexImage2D = glCompressedTexImage2D;
- _glCompressedTexSubImage1D = NULL;
- _glCompressedTexSubImage2D = glCompressedTexSubImage2D;
- _glGetCompressedTexImage = NULL;
- _glCompressedTexImage3D = NULL;
- _glCompressedTexSubImage3D = NULL;
- #ifdef OPENGLES_2
- if (_supports_3d_texture) {
- _glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)
- get_extension_func("glCompressedTexImage3DOES");
- _glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)
- get_extension_func("glCompressedTexSubImageOES");
- }
- #endif
- #else
- if (is_at_least_gl_version(1, 3)) {
- _supports_compressed_texture = true;
- _glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)
- get_extension_func("glCompressedTexImage1D");
- _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)
- get_extension_func("glCompressedTexImage2D");
- _glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)
- get_extension_func("glCompressedTexImage3D");
- _glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)
- get_extension_func("glCompressedTexSubImage1D");
- _glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)
- get_extension_func("glCompressedTexSubImage2D");
- _glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)
- get_extension_func("glCompressedTexSubImage3D");
- _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
- get_extension_func("glGetCompressedTexImage");
- } else if (has_extension("GL_ARB_texture_compression")) {
- _supports_compressed_texture = true;
- _glCompressedTexImage1D = (PFNGLCOMPRESSEDTEXIMAGE1DPROC)
- get_extension_func("glCompressedTexImage1DARB");
- _glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC)
- get_extension_func("glCompressedTexImage2DARB");
- _glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC)
- get_extension_func("glCompressedTexImage3DARB");
- _glCompressedTexSubImage1D = (PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC)
- get_extension_func("glCompressedTexSubImage1DARB");
- _glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC)
- get_extension_func("glCompressedTexSubImage2DARB");
- _glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC)
- get_extension_func("glCompressedTexSubImage3DARB");
- _glGetCompressedTexImage = (PFNGLGETCOMPRESSEDTEXIMAGEPROC)
- get_extension_func("glGetCompressedTexImageARB");
- }
- if (_supports_compressed_texture) {
- if (_glCompressedTexImage1D == NULL ||
- _glCompressedTexImage2D == NULL ||
- _glCompressedTexImage3D == NULL ||
- _glCompressedTexSubImage1D == NULL ||
- _glCompressedTexSubImage2D == NULL ||
- _glCompressedTexSubImage3D == NULL ||
- _glGetCompressedTexImage == NULL) {
- GLCAT.warning()
- << "Compressed textures advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _supports_compressed_texture = false;
- }
- }
- #endif
- if (_supports_compressed_texture) {
- #ifndef OPENGLES
- _compressed_texture_formats.set_bit(Texture::CM_on);
- #endif
- GLint num_compressed_formats = 0;
- glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_formats);
- GLint *formats = (GLint *)PANDA_MALLOC_ARRAY(num_compressed_formats * sizeof(GLint));
- glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
- for (int i = 0; i < num_compressed_formats; ++i) {
- switch (formats[i]) {
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- _compressed_texture_formats.set_bit(Texture::CM_dxt1);
- break;
- #ifdef OPENGLES
- case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
- case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
- _compressed_texture_formats.set_bit(Texture::CM_pvr1_2bpp);
- break;
- case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
- case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
- _compressed_texture_formats.set_bit(Texture::CM_pvr1_4bpp);
- break;
- #else
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- _compressed_texture_formats.set_bit(Texture::CM_dxt3);
- break;
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- _compressed_texture_formats.set_bit(Texture::CM_dxt5);
- break;
- case GL_COMPRESSED_RGB_FXT1_3DFX:
- case GL_COMPRESSED_RGBA_FXT1_3DFX:
- _compressed_texture_formats.set_bit(Texture::CM_fxt1);
- break;
- #endif
- default:
- break;
- }
- }
- PANDA_FREE_ARRAY(formats);
- }
- #ifdef OPENGLES_2
- _supports_bgr = false;
- #else
- _supports_bgr =
- has_extension("GL_EXT_bgra") || is_at_least_gl_version(1, 2);
- #endif
- #ifdef SUPPORT_FIXED_FUNCTION
- _supports_rescale_normal =
- !core_profile && gl_support_rescale_normal &&
- (has_extension("GL_EXT_rescale_normal") || is_at_least_gl_version(1, 2));
- #endif
- #ifdef OPENGLES
- _supports_packed_dabc = false;
- _supports_packed_ufloat = false;
- #else
- _supports_packed_dabc = is_at_least_gl_version(3, 2) ||
- has_extension("GL_ARB_vertex_array_bgra") ||
- has_extension("GL_EXT_vertex_array_bgra");
- _supports_packed_ufloat = is_at_least_gl_version(4, 4) ||
- has_extension("GL_ARB_vertex_type_10f_11f_11f_rev");
- #endif
- _supports_multisample =
- has_extension("GL_ARB_multisample") || is_at_least_gl_version(1, 3);
- #ifdef OPENGLES_2
- _supports_generate_mipmap = true;
- #else
- _supports_generate_mipmap =
- has_extension("GL_SGIS_generate_mipmap") || is_at_least_gl_version(1, 4) || is_at_least_gles_version(1, 1);
- #endif
- #ifdef OPENGLES
- _supports_tex_non_pow2 =
- has_extension("GL_OES_texture_npot");
- #else
- _supports_tex_non_pow2 =
- has_extension("GL_ARB_texture_non_power_of_two");
- #endif
- #ifdef OPENGLES_2
- _glActiveTexture = glActiveTexture;
- #else
- bool supports_multitexture = false;
- if (is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1)) {
- supports_multitexture = true;
- _glActiveTexture = (PFNGLACTIVETEXTUREPROC)
- get_extension_func("glActiveTexture");
- #ifdef SUPPORT_FIXED_FUNCTION
- _glClientActiveTexture = (PFNGLACTIVETEXTUREPROC)
- get_extension_func("glClientActiveTexture");
- #endif
- #ifdef SUPPORT_IMMEDIATE_MODE
- _glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)
- get_extension_func("glMultiTexCoord1f");
- _glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)
- get_extension_func("glMultiTexCoord2f");
- _glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)
- get_extension_func("glMultiTexCoord3f");
- _glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)
- get_extension_func("glMultiTexCoord4f");
- _glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC)
- get_extension_func("glMultiTexCoord1d");
- _glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC)
- get_extension_func("glMultiTexCoord2d");
- _glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC)
- get_extension_func("glMultiTexCoord3d");
- _glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC)
- get_extension_func("glMultiTexCoord4d");
- #endif
- } else if (has_extension("GL_ARB_multitexture")) {
- supports_multitexture = true;
- _glActiveTexture = (PFNGLACTIVETEXTUREPROC)
- get_extension_func("glActiveTextureARB");
- #ifdef SUPPORT_FIXED_FUNCTION
- _glClientActiveTexture = (PFNGLACTIVETEXTUREPROC)
- get_extension_func("glClientActiveTextureARB");
- #endif
- #ifdef SUPPORT_IMMEDIATE_MODE
- _glMultiTexCoord1f = (PFNGLMULTITEXCOORD1FPROC)
- get_extension_func("glMultiTexCoord1fARB");
- _glMultiTexCoord2f = (PFNGLMULTITEXCOORD2FPROC)
- get_extension_func("glMultiTexCoord2fARB");
- _glMultiTexCoord3f = (PFNGLMULTITEXCOORD3FPROC)
- get_extension_func("glMultiTexCoord3fARB");
- _glMultiTexCoord4f = (PFNGLMULTITEXCOORD4FPROC)
- get_extension_func("glMultiTexCoord4fARB");
- _glMultiTexCoord1d = (PFNGLMULTITEXCOORD1DPROC)
- get_extension_func("glMultiTexCoord1dARB");
- _glMultiTexCoord2d = (PFNGLMULTITEXCOORD2DPROC)
- get_extension_func("glMultiTexCoord2dARB");
- _glMultiTexCoord3d = (PFNGLMULTITEXCOORD3DPROC)
- get_extension_func("glMultiTexCoord3dARB");
- _glMultiTexCoord4d = (PFNGLMULTITEXCOORD4DPROC)
- get_extension_func("glMultiTexCoord4dARB");
- #endif
- } else {
- supports_multitexture = false;
- }
- if (supports_multitexture) {
- if (_glActiveTexture == NULL
- #ifdef SUPPORT_FIXED_FUNCTION
- || _glClientActiveTexture == NULL
- #endif
- #ifdef SUPPORT_IMMEDIATE_MODE
- || GLf(_glMultiTexCoord1) == NULL || GLf(_glMultiTexCoord2) == NULL
- || GLf(_glMultiTexCoord3) == NULL || GLf(_glMultiTexCoord4) == NULL
- #endif
- ) {
- GLCAT.warning()
- << "Multitexture advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- supports_multitexture = false;
- }
- }
- if (!supports_multitexture) {
- // Replace with dummy no-op functions.
- _glActiveTexture = null_glActiveTexture;
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- if (!supports_multitexture || core_profile) {
- _glClientActiveTexture = null_glActiveTexture;
- }
- #endif
- #endif // OPENGLES_2
- #ifdef OPENGLES
- if (has_extension("GL_ANGLE_depth_texture")) {
- // This extension provides both depth textures and depth-stencil support.
- _supports_depth_texture = true;
- _supports_depth_stencil = true;
- } else if (has_extension("GL_OES_depth_texture")) {
- _supports_depth_texture = true;
- _supports_depth_stencil = has_extension("GL_OES_packed_depth_stencil");
- }
- _supports_depth24 = has_extension("GL_OES_depth24");
- _supports_depth32 = has_extension("GL_OES_depth32");
- #else
- _supports_depth_texture = (is_at_least_gl_version(1, 4) ||
- has_extension("GL_ARB_depth_texture"));
- _supports_depth_stencil = (is_at_least_gl_version(3, 0) ||
- has_extension("GL_ARB_framebuffer_object") ||
- has_extension("GL_EXT_packed_depth_stencil"));
- #endif
- #ifdef OPENGLES_2
- if (gl_support_shadow_filter && _supports_depth_texture &&
- has_extension("GL_EXT_shadow_samplers")) {
- _supports_shadow_filter = true;
- }
- #else
- if (gl_support_shadow_filter &&
- _supports_depth_texture &&
- has_extension("GL_ARB_shadow") &&
- has_extension("GL_ARB_fragment_program_shadow")) {
- _supports_shadow_filter = true;
- }
- #endif
- // Actually, we can't keep forever disabling ARB_shadow on ATI cards,
- // since they do work correctly now. Maybe there is some feature
- // level we can check somewhere?
- /*if (_gl_vendor.substr(0,3)=="ATI") {
- // ATI drivers have never provided correct shadow support.
- _supports_shadow_filter = false;
- }*/
- #ifndef SUPPORT_FIXED_FUNCTION
- _supports_texture_combine = false;
- _supports_texture_saved_result = false;
- _supports_texture_dot3 = false;
- #else
- if (!core_profile) {
- _supports_texture_combine =
- has_extension("GL_ARB_texture_env_combine") || is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1);
- _supports_texture_saved_result =
- has_extension("GL_ARB_texture_env_crossbar") || has_extension("GL_OES_texture_env_crossbar") || is_at_least_gl_version(1, 4);
- _supports_texture_dot3 =
- has_extension("GL_ARB_texture_env_dot3") || is_at_least_gl_version(1, 3) || is_at_least_gles_version(1, 1);
- }
- #endif
- #ifdef OPENGLES_2
- _supports_buffers = true;
- _glGenBuffers = glGenBuffers;
- _glBindBuffer = glBindBuffer;
- _glBufferData = glBufferData;
- _glBufferSubData = glBufferSubData;
- _glDeleteBuffers = glDeleteBuffers;
- #else
- _supports_buffers = false;
- if (is_at_least_gl_version(1, 5) || is_at_least_gles_version(1, 1)) {
- _supports_buffers = true;
- _glGenBuffers = (PFNGLGENBUFFERSPROC)
- get_extension_func("glGenBuffers");
- _glBindBuffer = (PFNGLBINDBUFFERPROC)
- get_extension_func("glBindBuffer");
- _glBufferData = (PFNGLBUFFERDATAPROC)
- get_extension_func("glBufferData");
- _glBufferSubData = (PFNGLBUFFERSUBDATAPROC)
- get_extension_func("glBufferSubData");
- _glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)
- get_extension_func("glDeleteBuffers");
- }
- #ifndef OPENGLES_1
- else if (has_extension("GL_ARB_vertex_buffer_object")) {
- _supports_buffers = true;
- _glGenBuffers = (PFNGLGENBUFFERSPROC)
- get_extension_func("glGenBuffersARB");
- _glBindBuffer = (PFNGLBINDBUFFERPROC)
- get_extension_func("glBindBufferARB");
- _glBufferData = (PFNGLBUFFERDATAPROC)
- get_extension_func("glBufferDataARB");
- _glBufferSubData = (PFNGLBUFFERSUBDATAPROC)
- get_extension_func("glBufferSubDataARB");
- _glDeleteBuffers = (PFNGLDELETEBUFFERSPROC)
- get_extension_func("glDeleteBuffersARB");
- }
- #endif // OPENGLES_1
- if (_supports_buffers) {
- if (_glGenBuffers == NULL || _glBindBuffer == NULL ||
- _glBufferData == NULL || _glBufferSubData == NULL ||
- _glDeleteBuffers == NULL) {
- GLCAT.warning()
- << "Buffers advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _supports_buffers = false;
- }
- }
- #endif
- _supports_vao = false;
- if (is_at_least_gl_version(3, 0) || has_extension("GL_ARB_vertex_array_object")) {
- _supports_vao = true;
- _glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)
- get_extension_func("glBindVertexArray");
- _glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)
- get_extension_func("glDeleteVertexArrays");
- _glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)
- get_extension_func("glGenVertexArrays");
- } else if (has_extension("GL_OES_vertex_array_object")) {
- _supports_vao = true;
- _glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)
- get_extension_func("glBindVertexArrayOES");
- _glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC)
- get_extension_func("glDeleteVertexArraysOES");
- _glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)
- get_extension_func("glGenVertexArraysOES");
- }
- if (_supports_vao) {
- if (_glBindVertexArray == NULL || _glDeleteVertexArrays == NULL ||
- _glGenVertexArrays == NULL) {
- GLCAT.warning()
- << "Vertex array objects advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _supports_vao = false;
- }
- }
- // Check for GLSL support.
- #if defined(OPENGLES_1)
- _supports_glsl = false;
- _supports_geometry_shaders = false;
- _supports_tessellation_shaders = false;
- #elif defined(OPENGLES)
- _supports_glsl = true;
- _supports_geometry_shaders = false;
- _supports_tessellation_shaders = false;
- #else
- _supports_glsl = (_gl_shadlang_ver_major >= 1);
- _supports_tessellation_shaders = is_at_least_gl_version(4, 0) || has_extension("GL_ARB_tessellation_shader");
- if (is_at_least_gl_version(3, 2)) {
- _supports_geometry_shaders = true;
- _glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREARBPROC)
- get_extension_func("glFramebufferTexture");
- } else if (has_extension("GL_ARB_geometry_shader4")) {
- _supports_geometry_shaders = true;
- _glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREARBPROC)
- get_extension_func("glFramebufferTextureARB");
- _glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)
- get_extension_func("glProgramParameteriARB");
- } else if (has_extension("GL_EXT_geometry_shader4")) {
- _supports_geometry_shaders = true;
- _glFramebufferTexture = NULL;
- _glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)
- get_extension_func("glProgramParameteriEXT");
- } else {
- _supports_geometry_shaders = false;
- _glFramebufferTexture = NULL;
- }
- #endif
- _shader_caps._supports_glsl = _supports_glsl;
- // Check for support for other types of shaders that can be used by Cg.
- _supports_basic_shaders = false;
- #if defined(HAVE_CG) && !defined(OPENGLES)
- if (has_extension("GL_ARB_vertex_program") &&
- has_extension("GL_ARB_fragment_program")) {
- _supports_basic_shaders = true;
- _shader_caps._active_vprofile = (int)CG_PROFILE_ARBVP1;
- _shader_caps._active_fprofile = (int)CG_PROFILE_ARBFP1;
- _shader_caps._active_gprofile = (int)CG_PROFILE_UNKNOWN; // No geometry shader if only using basic
- if (basic_shaders_only) {
- // We're happy with ARB programs, thanks.
- } else if (has_extension("GL_NV_gpu_program5")) {
- _shader_caps._active_vprofile = (int)CG_PROFILE_GP5VP;
- _shader_caps._active_fprofile = (int)CG_PROFILE_GP5FP;
- _shader_caps._active_gprofile = (int)CG_PROFILE_GP5GP;
- } else if (has_extension("GL_NV_gpu_program4")) {
- _shader_caps._active_vprofile = (int)CG_PROFILE_GP4VP;
- _shader_caps._active_fprofile = (int)CG_PROFILE_GP4FP;
- _shader_caps._active_gprofile = (int)CG_PROFILE_GP4GP;
- } else if (has_extension("GL_NV_vertex_program3") &&
- has_extension("GL_NV_fragment_program2")) {
- _shader_caps._active_vprofile = (int)CG_PROFILE_VP40;
- _shader_caps._active_fprofile = (int)CG_PROFILE_FP40;
- _shader_caps._active_gprofile = (int)CG_PROFILE_UNKNOWN;
- } else if (has_extension("GL_NV_vertex_program2") &&
- has_extension("GL_NV_fragment_program")) {
- _shader_caps._active_vprofile = (int)CG_PROFILE_VP30;
- _shader_caps._active_fprofile = (int)CG_PROFILE_FP30;
- _shader_caps._active_gprofile = (int)CG_PROFILE_UNKNOWN;
- } else if (has_extension("GL_NV_vertex_program1_1") &&
- has_extension("GL_NV_texture_shader2") &&
- has_extension("GL_NV_register_combiners2")) {
- _shader_caps._active_vprofile = (int)CG_PROFILE_VP20;
- _shader_caps._active_fprofile = (int)CG_PROFILE_FP20;
- _shader_caps._active_gprofile = (int)CG_PROFILE_UNKNOWN;
- } else if (_supports_glsl) {
- // This is what will be available to non-NVIDIA cards. It is the last
- // option since it is slower to compile GLSL than the other options.
- _shader_caps._active_vprofile = (int)CG_PROFILE_GLSLV;
- _shader_caps._active_fprofile = (int)CG_PROFILE_GLSLF;
- if (_supports_geometry_shaders) {
- _shader_caps._active_gprofile = (int)CG_PROFILE_GLSLG;
- }
- }
- _shader_caps._ultimate_vprofile = (int)CG_PROFILE_VP40;
- _shader_caps._ultimate_fprofile = (int)CG_PROFILE_FP40;
- _shader_caps._ultimate_gprofile = (int)CG_PROFILE_GPU_GP;
- // Bug workaround for radeons.
- if (_shader_caps._active_fprofile == CG_PROFILE_ARBFP1) {
- if (has_extension("GL_ATI_draw_buffers")) {
- _shader_caps._bug_list.insert(Shader::SBUG_ati_draw_buffers);
- }
- }
- } else if (_supports_glsl) {
- // No, but we do support GLSL...
- _shader_caps._active_vprofile = (int)CG_PROFILE_GLSLV;
- _shader_caps._active_fprofile = (int)CG_PROFILE_GLSLF;
- if (_supports_geometry_shaders) {
- _shader_caps._active_gprofile = (int)CG_PROFILE_GLSLG;
- } else {
- _shader_caps._active_gprofile = (int)CG_PROFILE_UNKNOWN;
- }
- }
- #endif // HAVE_CG
- _supports_compute_shaders = false;
- #ifndef OPENGLES
- if (is_at_least_gl_version(4, 3) || has_extension("GL_ARB_compute_shader")) {
- _glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC)
- get_extension_func("glDispatchCompute");
- if (_glDispatchCompute != NULL) {
- _supports_compute_shaders = true;
- }
- }
- #endif
- #ifndef OPENGLES
- if (_supports_glsl) {
- _glAttachShader = (PFNGLATTACHSHADERPROC)
- get_extension_func("glAttachShader");
- _glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC)
- get_extension_func("glBindAttribLocation");
- _glCompileShader = (PFNGLCOMPILESHADERPROC)
- get_extension_func("glCompileShader");
- _glCreateProgram = (PFNGLCREATEPROGRAMPROC)
- get_extension_func("glCreateProgram");
- _glCreateShader = (PFNGLCREATESHADERPROC)
- get_extension_func("glCreateShader");
- _glDeleteProgram = (PFNGLDELETEPROGRAMPROC)
- get_extension_func("glDeleteProgram");
- _glDeleteShader = (PFNGLDELETESHADERPROC)
- get_extension_func("glDeleteShader");
- _glDetachShader = (PFNGLDETACHSHADERPROC)
- get_extension_func("glDetachShader");
- _glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC)
- get_extension_func("glDisableVertexAttribArray");
- _glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)
- get_extension_func("glEnableVertexAttribArray");
- _glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC)
- get_extension_func("glGetActiveAttrib");
- _glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC)
- get_extension_func("glGetActiveUniform");
- _glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC)
- get_extension_func("glGetAttribLocation");
- _glGetProgramiv = (PFNGLGETPROGRAMIVPROC)
- get_extension_func("glGetProgramiv");
- _glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)
- get_extension_func("glGetProgramInfoLog");
- _glGetShaderiv = (PFNGLGETSHADERIVPROC)
- get_extension_func("glGetShaderiv");
- _glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)
- get_extension_func("glGetShaderInfoLog");
- _glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)
- get_extension_func("glGetUniformLocation");
- _glLinkProgram = (PFNGLLINKPROGRAMPROC)
- get_extension_func("glLinkProgram");
- _glShaderSource = (PFNGLSHADERSOURCEPROC_P)
- get_extension_func("glShaderSource");
- _glUseProgram = (PFNGLUSEPROGRAMPROC)
- get_extension_func("glUseProgram");
- _glUniform4f = (PFNGLUNIFORM4FPROC)
- get_extension_func("glUniform4f");
- _glUniform1i = (PFNGLUNIFORM1IPROC)
- get_extension_func("glUniform1i");
- _glUniform1fv = (PFNGLUNIFORM1FVPROC)
- get_extension_func("glUniform1fv");
- _glUniform2fv = (PFNGLUNIFORM2FVPROC)
- get_extension_func("glUniform2fv");
- _glUniform3fv = (PFNGLUNIFORM3FVPROC)
- get_extension_func("glUniform3fv");
- _glUniform4fv = (PFNGLUNIFORM4FVPROC)
- get_extension_func("glUniform4fv");
- _glUniform1iv = (PFNGLUNIFORM1IVPROC)
- get_extension_func("glUniform1iv");
- _glUniform2iv = (PFNGLUNIFORM2IVPROC)
- get_extension_func("glUniform2iv");
- _glUniform3iv = (PFNGLUNIFORM3IVPROC)
- get_extension_func("glUniform3iv");
- _glUniform4iv = (PFNGLUNIFORM4IVPROC)
- get_extension_func("glUniform4iv");
- _glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC)
- get_extension_func("glUniformMatrix3fv");
- _glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)
- get_extension_func("glUniformMatrix4fv");
- _glValidateProgram = (PFNGLVALIDATEPROGRAMPROC)
- get_extension_func("glValidateProgram");
- _glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC)
- get_extension_func("glVertexAttrib4fv");
- _glVertexAttrib4dv = (PFNGLVERTEXATTRIB4DVPROC)
- get_extension_func("glVertexAttrib4dv");
- _glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)
- get_extension_func("glVertexAttribPointer");
- if (is_at_least_gl_version(3, 0)) {
- _glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC)
- get_extension_func("glVertexAttribIPointer");
- } else {
- _glVertexAttribIPointer = NULL;
- }
- if (has_extension("GL_ARB_vertex_attrib_64bit")) {
- _glVertexAttribLPointer = (PFNGLVERTEXATTRIBLPOINTERPROC)
- get_extension_func("glVertexAttribLPointer");
- } else {
- _glVertexAttribLPointer = NULL;
- }
- if (_supports_tessellation_shaders) {
- _glPatchParameteri = (PFNGLPATCHPARAMETERIPROC)
- get_extension_func("glPatchParameteri");
- }
- }
- #endif
- #ifdef OPENGLES_2
- _glAttachShader = glAttachShader;
- _glBindAttribLocation = glBindAttribLocation;
- _glCompileShader = glCompileShader;
- _glCreateProgram = glCreateProgram;
- _glCreateShader = glCreateShader;
- _glDeleteProgram = glDeleteProgram;
- _glDeleteShader = glDeleteShader;
- _glDetachShader = glDetachShader;
- _glDisableVertexAttribArray = glDisableVertexAttribArray;
- _glEnableVertexAttribArray = glEnableVertexAttribArray;
- _glGetActiveAttrib = glGetActiveAttrib;
- _glGetActiveUniform = glGetActiveUniform;
- _glGetAttribLocation = glGetAttribLocation;
- _glGetProgramiv = glGetProgramiv;
- _glGetProgramInfoLog = glGetProgramInfoLog;
- _glGetShaderiv = glGetShaderiv;
- _glGetShaderInfoLog = glGetShaderInfoLog;
- _glGetUniformLocation = glGetUniformLocation;
- _glLinkProgram = glLinkProgram;
- _glShaderSource = (PFNGLSHADERSOURCEPROC_P) glShaderSource;
- _glUseProgram = glUseProgram;
- _glUniform4f = glUniform4f;
- _glUniform1i = glUniform1i;
- _glUniform1fv = glUniform1fv;
- _glUniform2fv = glUniform2fv;
- _glUniform3fv = glUniform3fv;
- _glUniform4fv = glUniform4fv;
- _glUniformMatrix3fv = glUniformMatrix3fv;
- _glUniformMatrix4fv = glUniformMatrix4fv;
- _glValidateProgram = glValidateProgram;
- _glVertexAttrib4fv = glVertexAttrib4fv;
- _glVertexAttrib4dv = NULL;
- _glVertexAttribPointer = glVertexAttribPointer;
- _glVertexAttribIPointer = NULL;
- _glVertexAttribLPointer = NULL;
- #endif
- #ifndef OPENGLES_1
- // We need to have a default shader to apply in case
- // something didn't happen to have a shader applied, or
- // if it failed to compile. This default shader just outputs
- // a red color, indicating that something went wrong.
- if (_default_shader == NULL && core_profile) {
- _default_shader = Shader::make(Shader::SL_GLSL, default_vshader, default_fshader);
- }
- #endif
- #ifndef OPENGLES
- // Check for uniform buffers.
- if (is_at_least_gl_version(3, 1) || has_extension("GL_ARB_uniform_buffer_object")) {
- _supports_uniform_buffers = true;
- _glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC)
- get_extension_func("glGetActiveUniformsiv");
- _glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC)
- get_extension_func("glGetActiveUniformBlockiv");
- _glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC)
- get_extension_func("glGetActiveUniformBlockName");
- } else {
- _supports_uniform_buffers = false;
- }
- #else
- _supports_uniform_buffers = false;
- #endif
- // Check whether we support geometry instancing and instanced vertex attribs.
- #if defined(OPENGLES_1)
- _supports_vertex_attrib_divisor = false;
- _supports_geometry_instancing = false;
- #elif defined(OPENGLES_2)
- if (has_extension("GL_ANGLE_instanced_arrays")) {
- // This extension has both things in one.
- #ifdef __EMSCRIPTEN__
- // Work around bug - it doesn't allow ANGLE suffix in getProcAddress.
- _glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
- get_extension_func("glVertexAttribDivisor");
- _glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)
- get_extension_func("glDrawArraysInstanced");
- _glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)
- get_extension_func("glDrawElementsInstanced");
- #else
- _glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
- get_extension_func("glVertexAttribDivisorANGLE");
- _glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)
- get_extension_func("glDrawArraysInstancedANGLE");
- _glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)
- get_extension_func("glDrawElementsInstancedANGLE");
- #endif
- _supports_vertex_attrib_divisor = true;
- _supports_geometry_instancing = true;
- } else {
- // Check separately for geometry instancing and instanced attribs.
- if (has_extension("GL_EXT_draw_instanced")) {
- _glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)
- get_extension_func("glDrawArraysInstancedEXT");
- _glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)
- get_extension_func("glDrawElementsInstancedEXT");
- _supports_geometry_instancing = true;
- } else if (has_extension("GL_NV_draw_instanced")) {
- _glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)
- get_extension_func("glDrawArraysInstancedNV");
- _glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)
- get_extension_func("glDrawElementsInstancedNV");
- _supports_geometry_instancing = true;
- } else {
- _supports_geometry_instancing = false;
- }
- if (has_extension("GL_EXT_instanced_arrays")) {
- _glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
- get_extension_func("glVertexAttribDivisorEXT");
- _supports_vertex_attrib_divisor = true;
- } else if (has_extension("GL_NV_instanced_arrays")) {
- _glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
- get_extension_func("glVertexAttribDivisorNV");
- _supports_vertex_attrib_divisor = true;
- } else {
- _supports_vertex_attrib_divisor = false;
- }
- }
- #else
- if (is_at_least_gl_version(3, 3)) {
- // This feature is in OpenGL core as of 3.3.
- _glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
- get_extension_func("glVertexAttribDivisor");
- _supports_vertex_attrib_divisor = true;
- } else if (has_extension("GL_ARB_instanced_arrays")) {
- _glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC)
- get_extension_func("glVertexAttribDivisorARB");
- _supports_vertex_attrib_divisor = true;
- } else {
- _supports_vertex_attrib_divisor = false;
- }
- // Some drivers expose one extension, some expose the other.
- if (is_at_least_gl_version(3, 1)) {
- _glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)
- get_extension_func("glDrawArraysInstanced");
- _glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)
- get_extension_func("glDrawElementsInstanced");
- _supports_geometry_instancing = true;
- } else if (has_extension("GL_ARB_draw_instanced")) {
- _glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)
- get_extension_func("glDrawArraysInstancedARB");
- _glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)
- get_extension_func("glDrawElementsInstancedARB");
- _supports_geometry_instancing = true;
- } else if (has_extension("GL_EXT_draw_instanced")) {
- _glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC)
- get_extension_func("glDrawArraysInstancedEXT");
- _glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC)
- get_extension_func("glDrawElementsInstancedEXT");
- _supports_geometry_instancing = true;
- } else {
- _glDrawElementsInstanced = 0;
- _glDrawArraysInstanced = 0;
- _supports_geometry_instancing = false;
- }
- #endif
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing) {
- if (_glDrawArraysInstanced == NULL || _glDrawElementsInstanced == NULL) {
- GLCAT.warning()
- << "Geometry instancing advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _supports_geometry_instancing = false;
- }
- }
- if (_supports_vertex_attrib_divisor) {
- if (_glVertexAttribDivisor == NULL) {
- GLCAT.warning()
- << "Instanced vertex arrays advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _supports_vertex_attrib_divisor = false;
- }
- }
- #endif
- #ifdef OPENGLES_2
- // In OpenGL ES 2.x, FBO's are supported in the core.
- _supports_framebuffer_object = true;
- _glIsRenderbuffer = glIsRenderbuffer;
- _glBindRenderbuffer = glBindRenderbuffer;
- _glDeleteRenderbuffers = glDeleteRenderbuffers;
- _glGenRenderbuffers = glGenRenderbuffers;
- _glRenderbufferStorage = glRenderbufferStorage;
- _glGetRenderbufferParameteriv = glGetRenderbufferParameteriv;
- _glIsFramebuffer = glIsFramebuffer;
- _glBindFramebuffer = glBindFramebuffer;
- _glDeleteFramebuffers = glDeleteFramebuffers;
- _glGenFramebuffers = glGenFramebuffers;
- _glCheckFramebufferStatus = glCheckFramebufferStatus;
- _glFramebufferTexture1D = NULL;
- _glFramebufferTexture2D = glFramebufferTexture2D;
- _glFramebufferRenderbuffer = glFramebufferRenderbuffer;
- _glGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;
- _glGenerateMipmap = glGenerateMipmap;
- #else
- //TODO: add ARB/3.0 version
- _supports_framebuffer_object = false;
- if (has_extension("GL_EXT_framebuffer_object")) {
- _supports_framebuffer_object = true;
- _glIsRenderbuffer = (PFNGLISRENDERBUFFEREXTPROC)
- get_extension_func("glIsRenderbufferEXT");
- _glBindRenderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)
- get_extension_func("glBindRenderbufferEXT");
- _glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC)
- get_extension_func("glDeleteRenderbuffersEXT");
- _glGenRenderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)
- get_extension_func("glGenRenderbuffersEXT");
- _glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)
- get_extension_func("glRenderbufferStorageEXT");
- _glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)
- get_extension_func("glGetRenderbufferParameterivEXT");
- _glIsFramebuffer = (PFNGLISFRAMEBUFFEREXTPROC)
- get_extension_func("glIsFramebufferEXT");
- _glBindFramebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)
- get_extension_func("glBindFramebufferEXT");
- _glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
- get_extension_func("glDeleteFramebuffersEXT");
- _glGenFramebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)
- get_extension_func("glGenFramebuffersEXT");
- _glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
- get_extension_func("glCheckFramebufferStatusEXT");
- _glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)
- get_extension_func("glFramebufferTexture1DEXT");
- _glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
- get_extension_func("glFramebufferTexture2DEXT");
- _glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)
- get_extension_func("glFramebufferTexture3DEXT");
- _glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
- get_extension_func("glFramebufferRenderbufferEXT");
- _glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)
- get_extension_func("glGetFramebufferAttachmentParameterivEXT");
- _glGenerateMipmap = (PFNGLGENERATEMIPMAPEXTPROC)
- get_extension_func("glGenerateMipmapEXT");
- }
- #ifdef OPENGLES
- else if (has_extension("GL_OES_framebuffer_object")) {
- _supports_framebuffer_object = true;
- _glIsRenderbuffer = (PFNGLISRENDERBUFFEROESPROC)
- get_extension_func("glIsRenderbufferOES");
- _glBindRenderbuffer = (PFNGLBINDRENDERBUFFEROESPROC)
- get_extension_func("glBindRenderbufferOES");
- _glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSOESPROC)
- get_extension_func("glDeleteRenderbuffersOES");
- _glGenRenderbuffers = (PFNGLGENRENDERBUFFERSOESPROC)
- get_extension_func("glGenRenderbuffersOES");
- _glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEOESPROC)
- get_extension_func("glRenderbufferStorageOES");
- _glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVOESPROC)
- get_extension_func("glGetRenderbufferParameterivOES");
- _glIsFramebuffer = (PFNGLISFRAMEBUFFEROESPROC)
- get_extension_func("glIsFramebufferOES");
- _glBindFramebuffer = (PFNGLBINDFRAMEBUFFEROESPROC)
- get_extension_func("glBindFramebufferOES");
- _glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSOESPROC)
- get_extension_func("glDeleteFramebuffersOES");
- _glGenFramebuffers = (PFNGLGENFRAMEBUFFERSOESPROC)
- get_extension_func("glGenFramebuffersOES");
- _glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSOESPROC)
- get_extension_func("glCheckFramebufferStatusOES");
- _glFramebufferTexture1D = NULL;
- _glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DOESPROC)
- get_extension_func("glFramebufferTexture2DOES");
- _glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFEROESPROC)
- get_extension_func("glFramebufferRenderbufferOES");
- _glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVOESPROC)
- get_extension_func("glGetFramebufferAttachmentParameterivOES");
- _glGenerateMipmap = (PFNGLGENERATEMIPMAPOESPROC)
- get_extension_func("glGenerateMipmapOES");
- }
- #endif // OPENGLES
- #endif
- _supports_framebuffer_multisample = false;
- if ( has_extension("GL_EXT_framebuffer_multisample") ) {
- _supports_framebuffer_multisample = true;
- _glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)
- get_extension_func("glRenderbufferStorageMultisampleEXT");
- }
- #ifndef OPENGLES
- _supports_framebuffer_multisample_coverage_nv = false;
- if ( has_extension("GL_NV_framebuffer_multisample_coverage") ) {
- _supports_framebuffer_multisample_coverage_nv = true;
- _glRenderbufferStorageMultisampleCoverage = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLECOVERAGENVPROC)
- get_extension_func("glRenderbufferStorageMultisampleCoverageNV");
- }
- #endif
- #ifndef OPENGLES_1
- _supports_framebuffer_blit = false;
- if ( has_extension("GL_EXT_framebuffer_blit") ) {
- _supports_framebuffer_blit = true;
- _glBlitFramebuffer = (PFNGLBLITFRAMEBUFFEREXTPROC)
- get_extension_func("glBlitFramebufferEXT");
- }
- #endif
- #if defined(OPENGLES_1)
- _glDrawBuffers = NULL;
- _glClearBufferfv = NULL;
- _max_color_targets = 1;
- #elif defined(OPENGLES_2)
- if (has_extension("GL_EXT_draw_buffers")) {
- _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
- get_extension_func("glDrawBuffersEXT");
- } else if (has_extension("GL_NV_draw_buffers")) {
- _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
- get_extension_func("glDrawBuffersNV");
- }
- #else
- if (is_at_least_gl_version(2, 0)) {
- _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
- get_extension_func("glDrawBuffers");
- } else if (has_extension("GL_ARB_draw_buffers")) {
- _glDrawBuffers = (PFNGLDRAWBUFFERSPROC)
- get_extension_func("glDrawBuffersARB");
- }
- #endif
- #ifndef OPENGLES_1
- _max_color_targets = 1;
- if (_glDrawBuffers != 0) {
- GLint max_draw_buffers = 0;
- glGetIntegerv(GL_MAX_DRAW_BUFFERS, &max_draw_buffers);
- _max_color_targets = max_draw_buffers;
- }
- #endif // !OPENGLES_1
- #ifndef OPENGLES
- if (is_at_least_gl_version(3, 0)) {
- _glClearBufferfv = (PFNGLCLEARBUFFERFVPROC)
- get_extension_func("glClearBufferfv");
- } else {
- _glClearBufferfv = NULL;
- }
- #endif // !OPENGLES
- #ifndef OPENGLES
- _supports_viewport_arrays = false;
- if (is_at_least_gl_version(4, 1) || has_extension("GL_ARB_viewport_array")) {
- _glViewportArrayv = (PFNGLVIEWPORTARRAYVPROC)
- get_extension_func("glViewportArrayv");
- _glScissorArrayv = (PFNGLSCISSORARRAYVPROC)
- get_extension_func("glScissorArrayv");
- _glDepthRangeArrayv = (PFNGLDEPTHRANGEARRAYVPROC)
- get_extension_func("glDepthRangeArrayv");
- if (_glViewportArrayv == NULL || _glScissorArrayv == NULL || _glDepthRangeArrayv == NULL) {
- GLCAT.warning()
- << "Viewport arrays advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- } else {
- _supports_viewport_arrays = true;
- }
- }
- #endif // !OPENGLES
- _max_fb_samples = 0;
- if (_supports_framebuffer_multisample) {
- GLint max_samples;
- glGetIntegerv(GL_MAX_SAMPLES_EXT, &max_samples);
- _max_fb_samples = max_samples;
- }
- _supports_occlusion_query = false;
- #ifndef OPENGLES
- if (gl_support_occlusion_query) {
- if (is_at_least_gl_version(1, 5)) {
- _supports_occlusion_query = true;
- _glGenQueries = (PFNGLGENQUERIESPROC)
- get_extension_func("glGenQueries");
- _glBeginQuery = (PFNGLBEGINQUERYPROC)
- get_extension_func("glBeginQuery");
- _glEndQuery = (PFNGLENDQUERYPROC)
- get_extension_func("glEndQuery");
- _glDeleteQueries = (PFNGLDELETEQUERIESPROC)
- get_extension_func("glDeleteQueries");
- _glGetQueryiv = (PFNGLGETQUERYIVPROC)
- get_extension_func("glGetQueryiv");
- _glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)
- get_extension_func("glGetQueryObjectuiv");
- } else if (has_extension("GL_ARB_occlusion_query")) {
- _supports_occlusion_query = true;
- _glGenQueries = (PFNGLGENQUERIESPROC)
- get_extension_func("glGenQueriesARB");
- _glBeginQuery = (PFNGLBEGINQUERYPROC)
- get_extension_func("glBeginQueryARB");
- _glEndQuery = (PFNGLENDQUERYPROC)
- get_extension_func("glEndQueryARB");
- _glDeleteQueries = (PFNGLDELETEQUERIESPROC)
- get_extension_func("glDeleteQueriesARB");
- _glGetQueryiv = (PFNGLGETQUERYIVPROC)
- get_extension_func("glGetQueryivARB");
- _glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC)
- get_extension_func("glGetQueryObjectuivARB");
- }
- }
- if (_supports_occlusion_query) {
- if (_glGenQueries == NULL || _glBeginQuery == NULL ||
- _glEndQuery == NULL || _glDeleteQueries == NULL ||
- _glGetQueryiv == NULL || _glGetQueryObjectuiv == NULL) {
- GLCAT.warning()
- << "Occlusion queries advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
- _supports_occlusion_query = false;
- } else {
- GLint num_bits;
- _glGetQueryiv(GL_SAMPLES_PASSED, GL_QUERY_COUNTER_BITS, &num_bits);
- if (num_bits == 0) {
- _supports_occlusion_query = false;
- }
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "Occlusion query counter provides " << num_bits << " bits.\n";
- }
- }
- }
- #endif // !OPENGLES
- _supports_timer_query = false;
- #if defined(DO_PSTATS) && !defined(OPENGLES)
- if (is_at_least_gl_version(3, 3) || has_extension("GL_ARB_timer_query")) {
- _supports_timer_query = true;
- _glQueryCounter = (PFNGLQUERYCOUNTERPROC)
- get_extension_func("glQueryCounter");
- _glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC)
- get_extension_func("glGetQueryObjecti64v");
- _glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC)
- get_extension_func("glGetQueryObjectui64v");
- _glGetInteger64v = (PFNGLGETINTEGER64VPROC)
- get_extension_func("glGetInteger64v");
- }
- #endif
- #ifdef OPENGLES_2
- // In OpenGL ES 2.x, this is supported in the core.
- _glBlendEquation = glBlendEquation;
- #else
- _glBlendEquation = NULL;
- bool supports_blend_equation = false;
- if (is_at_least_gl_version(1, 2)) {
- supports_blend_equation = true;
- _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
- get_extension_func("glBlendEquation");
- } else if (has_extension("GL_OES_blend_subtract")) {
- supports_blend_equation = true;
- _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
- get_extension_func("glBlendEquationOES");
- } else if (has_extension("GL_EXT_blend_minmax")) {
- supports_blend_equation = true;
- _glBlendEquation = (PFNGLBLENDEQUATIONPROC)
- get_extension_func("glBlendEquationEXT");
- }
- if (supports_blend_equation && _glBlendEquation == NULL) {
- GLCAT.warning()
- << "BlendEquation advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
- }
- if (_glBlendEquation == NULL) {
- _glBlendEquation = null_glBlendEquation;
- }
- #endif
- #ifdef OPENGLES_2
- // In OpenGL ES 2.x, this is supported in the core.
- _glBlendColor = glBlendColor;
- #else
- _glBlendColor = NULL;
- bool supports_blend_color = false;
- if (is_at_least_gl_version(1, 2)) {
- supports_blend_color = true;
- _glBlendColor = (PFNGLBLENDCOLORPROC)
- get_extension_func("glBlendColor");
- } else if (has_extension("GL_EXT_blend_color")) {
- supports_blend_color = true;
- _glBlendColor = (PFNGLBLENDCOLORPROC)
- get_extension_func("glBlendColorEXT");
- }
- if (supports_blend_color && _glBlendColor == NULL) {
- GLCAT.warning()
- << "BlendColor advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
- }
- if (_glBlendColor == NULL) {
- _glBlendColor = null_glBlendColor;
- }
- #endif
- #ifdef OPENGLES
- _edge_clamp = GL_CLAMP_TO_EDGE;
- #else
- _edge_clamp = GL_CLAMP;
- if (has_extension("GL_SGIS_texture_edge_clamp") ||
- is_at_least_gl_version(1, 2) || is_at_least_gles_version(1, 1)) {
- _edge_clamp = GL_CLAMP_TO_EDGE;
- }
- #endif
- _border_clamp = _edge_clamp;
- #ifndef OPENGLES
- if (gl_support_clamp_to_border &&
- (has_extension("GL_ARB_texture_border_clamp") ||
- is_at_least_gl_version(1, 3))) {
- _border_clamp = GL_CLAMP_TO_BORDER;
- }
- #endif
- #ifdef OPENGLES_2
- _mirror_repeat = GL_MIRRORED_REPEAT;
- #else
- _mirror_repeat = GL_REPEAT;
- if (has_extension("GL_ARB_texture_mirrored_repeat") ||
- is_at_least_gl_version(1, 4) ||
- has_extension("GL_OES_texture_mirrored_repeat")) {
- _mirror_repeat = GL_MIRRORED_REPEAT;
- }
- #endif
- _mirror_clamp = _edge_clamp;
- _mirror_edge_clamp = _edge_clamp;
- _mirror_border_clamp = _border_clamp;
- #ifndef OPENGLES
- if (has_extension("GL_EXT_texture_mirror_clamp")) {
- _mirror_clamp = GL_MIRROR_CLAMP_EXT;
- _mirror_edge_clamp = GL_MIRROR_CLAMP_TO_EDGE_EXT;
- _mirror_border_clamp = GL_MIRROR_CLAMP_TO_BORDER_EXT;
- }
- #endif
- if (_supports_multisample) {
- GLint sample_buffers = 0;
- glGetIntegerv(GL_SAMPLE_BUFFERS, &sample_buffers);
- if (sample_buffers != 1) {
- // Even if the API supports multisample, we might have ended up
- // with a framebuffer that doesn't have any multisample bits.
- // (It's also possible the graphics card doesn't provide any
- // framebuffers with multisample.) In this case, we don't
- // really support the multisample API's, since they won't do
- // anything.
- _supports_multisample = false;
- }
- }
- GLint max_texture_size = 0;
- GLint max_3d_texture_size = 0;
- GLint max_2d_texture_array_layers = 0;
- GLint max_cube_map_size = 0;
- GLint max_buffer_texture_size = 0;
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
- _max_texture_dimension = max_texture_size;
- if (_supports_3d_texture) {
- #ifndef OPENGLES_1
- glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &max_3d_texture_size);
- #endif
- _max_3d_texture_dimension = max_3d_texture_size;
- } else {
- _max_3d_texture_dimension = 0;
- }
- #ifndef OPENGLES
- if(_supports_2d_texture_array) {
- glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS_EXT, &max_2d_texture_array_layers);
- _max_2d_texture_array_layers = max_2d_texture_array_layers;
- }
- #endif
- if (_supports_cube_map) {
- glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &max_cube_map_size);
- _max_cube_map_dimension = max_cube_map_size;
- } else {
- _max_cube_map_dimension = 0;
- }
- #ifndef OPENGLES
- if (_supports_buffer_texture) {
- glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &max_buffer_texture_size);
- _max_buffer_texture_size = max_buffer_texture_size;
- } else {
- _max_buffer_texture_size = 0;
- }
- #endif // !OPENGLES
- GLint max_elements_vertices = 0, max_elements_indices = 0;
- #ifndef OPENGLES
- glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &max_elements_vertices);
- glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &max_elements_indices);
- if (max_elements_vertices > 0) {
- _max_vertices_per_array = max_elements_vertices;
- }
- if (max_elements_indices > 0) {
- _max_vertices_per_primitive = max_elements_indices;
- }
- #endif // OPENGLES
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "max texture dimension = " << _max_texture_dimension
- << ", max 3d texture = " << _max_3d_texture_dimension
- << ", max 2d texture array = " << max_2d_texture_array_layers
- << ", max cube map = " << _max_cube_map_dimension << "\n";
- GLCAT.debug()
- << "max_elements_vertices = " << max_elements_vertices
- << ", max_elements_indices = " << max_elements_indices << "\n";
- if (_supports_buffers) {
- if (vertex_buffers) {
- GLCAT.debug()
- << "vertex buffer objects are supported.\n";
- } else {
- GLCAT.debug()
- << "vertex buffer objects are supported (but not enabled).\n";
- }
- } else {
- GLCAT.debug()
- << "vertex buffer objects are NOT supported.\n";
- }
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (!vertex_arrays) {
- GLCAT.debug()
- << "immediate mode commands will be used instead of vertex arrays.\n";
- }
- #endif
- if (!_supports_compressed_texture) {
- GLCAT.debug()
- << "Texture compression is not supported.\n";
- } else {
- GLint num_compressed_formats = 0;
- glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &num_compressed_formats);
- if (num_compressed_formats == 0) {
- GLCAT.debug()
- << "No specific compressed texture formats are supported.\n";
- } else {
- #ifndef NDEBUG
- GLCAT.debug()
- << "Supported compressed texture formats:\n";
- GLint *formats = (GLint *)alloca(num_compressed_formats * sizeof(GLint));
- glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, formats);
- for (int i = 0; i < num_compressed_formats; ++i) {
- const char *format_str = get_compressed_format_string(formats[i]);
- if (format_str != NULL) {
- GLCAT.debug(false) << " " << format_str << '\n';
- } else {
- GLCAT.debug(false)
- << " Unknown compressed format 0x" << hex << formats[i]
- << dec << "\n";
- }
- }
- #endif
- }
- }
- }
- _num_active_texture_stages = 0;
- // Check availability of anisotropic texture filtering.
- _supports_anisotropy = false;
- _max_anisotropy = 1.0;
- if (has_extension("GL_EXT_texture_filter_anisotropic")) {
- GLfloat max_anisotropy;
- glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &max_anisotropy);
- _max_anisotropy = (PN_stdfloat)max_anisotropy;
- _supports_anisotropy = true;
- }
- // Check availability of image read/write functionality in shaders.
- _max_image_units = 0;
- #ifndef OPENGLES
- if (is_at_least_gl_version(4, 2) || has_extension("GL_ARB_shader_image_load_store")) {
- _glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)
- get_extension_func("glBindImageTexture");
- _glMemoryBarrier = (PFNGLMEMORYBARRIERPROC)
- get_extension_func("glMemoryBarrier");
- glGetIntegerv(GL_MAX_IMAGE_UNITS, &_max_image_units);
- } else if (has_extension("GL_EXT_shader_image_load_store")) {
- _glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC)
- get_extension_func("glBindImageTextureEXT");
- _glMemoryBarrier = (PFNGLMEMORYBARRIERPROC)
- get_extension_func("glMemoryBarrierEXT");
- glGetIntegerv(GL_MAX_IMAGE_UNITS_EXT, &_max_image_units);
- } else {
- _glBindImageTexture = NULL;
- _glMemoryBarrier = NULL;
- }
- _supports_sampler_objects = false;
- #ifndef OPENGLES
- if (gl_support_sampler_objects &&
- ((is_at_least_gl_version(3, 3) || has_extension("GL_ARB_sampler_objects")))) {
- _glGenSamplers = (PFNGLGENSAMPLERSPROC) get_extension_func("glGenSamplers");
- _glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) get_extension_func("glDeleteSamplers");
- _glBindSampler = (PFNGLBINDSAMPLERPROC) get_extension_func("glBindSampler");
- _glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) get_extension_func("glSamplerParameteri");
- _glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) get_extension_func("glSamplerParameteriv");
- _glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) get_extension_func("glSamplerParameterf");
- _glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) get_extension_func("glSamplerParameterfv");
- if (_glGenSamplers == NULL || _glDeleteSamplers == NULL ||
- _glBindSampler == NULL || _glSamplerParameteri == NULL ||
- _glSamplerParameteriv == NULL || _glSamplerParameterf == NULL ||
- _glSamplerParameterfv == NULL) {
- GLCAT.warning()
- << "GL_ARB_sampler_objects advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
- } else {
- _supports_sampler_objects = true;
- }
- }
- #endif // OPENGLES
- // Check availability of multi-bind functions.
- _supports_multi_bind = false;
- if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_multi_bind")) {
- _glBindTextures = (PFNGLBINDTEXTURESPROC)
- get_extension_func("glBindTextures");
- _glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC)
- get_extension_func("glBindImageTextures");
- #ifndef OPENGLES
- if (_supports_sampler_objects) {
- _glBindSamplers = (PFNGLBINDSAMPLERSPROC)
- get_extension_func("glBindSamplers");
- }
- #endif // OPENGLES
- if (_glBindTextures != NULL && _glBindImageTextures != NULL) {
- _supports_multi_bind = true;
- } else {
- GLCAT.warning()
- << "ARB_multi_bind advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
- }
- }
- if (is_at_least_gl_version(4, 3) || has_extension("GL_ARB_internalformat_query2")) {
- _glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC)
- get_extension_func("glGetInternalformativ");
- if (_glGetInternalformativ == NULL) {
- GLCAT.warning()
- << "ARB_internalformat_query2 advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
- }
- }
- _supports_bindless_texture = false;
- if (has_extension("GL_ARB_bindless_texture")) {
- _glGetTextureHandle = (PFNGLGETTEXTUREHANDLEPROC)
- get_extension_func("glGetTextureHandleARB");
- _glGetTextureSamplerHandle = (PFNGLGETTEXTURESAMPLERHANDLEPROC)
- get_extension_func("glGetTextureSamplerHandleARB");
- _glMakeTextureHandleResident = (PFNGLMAKETEXTUREHANDLERESIDENTPROC)
- get_extension_func("glMakeTextureHandleResidentARB");
- _glUniformHandleui64 = (PFNGLUNIFORMHANDLEUI64PROC)
- get_extension_func("glUniformHandleui64ARB");
- if (_glGetTextureHandle == NULL || _glMakeTextureHandleResident == NULL ||
- _glUniformHandleui64 == NULL) {
- GLCAT.warning()
- << "GL_ARB_bindless_texture advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
- } else {
- _supports_bindless_texture = true;
- }
- }
- #endif
- #ifndef OPENGLES
- _supports_get_program_binary = false;
- if (is_at_least_gl_version(4, 1) || has_extension("GL_ARB_get_program_binary")) {
- _glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC)
- get_extension_func("glGetProgramBinary");
- _glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC)
- get_extension_func("glProgramParameteri");
- if (_glGetProgramBinary != NULL && _glProgramParameteri != NULL) {
- _supports_get_program_binary = true;
- }
- }
- #endif
- report_my_gl_errors();
- if (core_profile) {
- //TODO: better detection mechanism?
- _supports_stencil = true;
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- else if (support_stencil) {
- GLint num_stencil_bits;
- glGetIntegerv(GL_STENCIL_BITS, &num_stencil_bits);
- _supports_stencil = (num_stencil_bits != 0);
- }
- #endif
- _supports_stencil_wrap =
- has_extension("GL_EXT_stencil_wrap") || has_extension("GL_OES_stencil_wrap");
- _supports_two_sided_stencil = false;
- #ifndef OPENGLES
- if (has_extension("GL_EXT_stencil_two_side")) {
- _glActiveStencilFaceEXT = (PFNGLACTIVESTENCILFACEEXTPROC)
- get_extension_func("glActiveStencilFaceEXT");
- _supports_two_sided_stencil = true;
- } else {
- _glActiveStencilFaceEXT = 0;
- }
- #endif
- // Ensure the initial state is what we say it should be (in some
- // cases, we don't want the GL default settings; in others, we have
- // to force the point with some drivers that aren't strictly
- // compliant w.r.t. initial settings).
- glFrontFace(GL_CCW);
- #ifndef OPENGLES_2
- glDisable(GL_LINE_SMOOTH);
- #endif
- #ifdef SUPPORT_FIXED_FUNCTION
- if (!core_profile) {
- glDisable(GL_POINT_SMOOTH);
- }
- #endif
- #ifndef OPENGLES
- glDisable(GL_POLYGON_SMOOTH);
- #endif // OPENGLES
- #ifndef OPENGLES_2
- if (_supports_multisample) {
- glDisable(GL_MULTISAMPLE);
- }
- #endif
- // Set up all the enabled/disabled flags to GL's known initial
- // values: everything off.
- _multisample_mode = 0;
- _line_smooth_enabled = false;
- _point_smooth_enabled = false;
- _polygon_smooth_enabled = false;
- _stencil_test_enabled = false;
- _blend_enabled = false;
- _depth_test_enabled = false;
- _fog_enabled = false;
- _alpha_test_enabled = false;
- _polygon_offset_enabled = false;
- _flat_shade_model = false;
- _decal_level = 0;
- _active_color_write_mask = ColorWriteAttrib::C_all;
- _tex_gen_point_sprite = false;
- #ifndef OPENGLES
- // Dither is on by default in GL; let's turn it off
- glDisable(GL_DITHER);
- #endif // OPENGLES
- _dithering_enabled = false;
- #ifndef OPENGLES_1
- _current_shader = (Shader *)NULL;
- _current_shader_context = (ShaderContext *)NULL;
- _vertex_array_shader = (Shader *)NULL;
- _vertex_array_shader_context = (ShaderContext *)NULL;
- _texture_binding_shader = (Shader *)NULL;
- _texture_binding_shader_context = (ShaderContext *)NULL;
- #endif
- // Count the max number of lights
- _max_lights = 0;
- #ifdef SUPPORT_FIXED_FUNCTION
- if (!core_profile) {
- GLint max_lights = 0;
- glGetIntegerv(GL_MAX_LIGHTS, &max_lights);
- _max_lights = max_lights;
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "max lights = " << _max_lights << "\n";
- }
- }
- #endif
- // Count the max number of clipping planes
- _max_clip_planes = 0;
- #ifdef SUPPORT_FIXED_FUNCTION
- if (!core_profile) {
- GLint max_clip_planes = 0;
- glGetIntegerv(GL_MAX_CLIP_PLANES, &max_clip_planes);
- _max_clip_planes = max_clip_planes;
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "max clip planes = " << _max_clip_planes << "\n";
- }
- }
- #endif
- _max_texture_stages = 1;
- #ifdef SUPPORT_FIXED_FUNCTION
- if (supports_multitexture && !core_profile) {
- GLint max_texture_stages = 0;
- glGetIntegerv(GL_MAX_TEXTURE_UNITS, &max_texture_stages);
- _max_texture_stages = max_texture_stages;
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "max texture stages = " << _max_texture_stages << "\n";
- }
- }
- #endif
- _current_vbuffer_index = 0;
- _current_ibuffer_index = 0;
- _current_vao_index = 0;
- _current_fbo = 0;
- _auto_antialias_mode = false;
- _render_mode = RenderModeAttrib::M_filled;
- _point_size = 1.0f;
- _point_perspective = false;
- report_my_gl_errors();
- #ifdef SUPPORT_FIXED_FUNCTION
- if (!core_profile) {
- if (gl_cheap_textures) {
- GLCAT.info()
- << "Setting glHint() for fastest textures.\n";
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
- }
- // Use per-vertex fog if per-pixel fog requires SW renderer
- glHint(GL_FOG_HINT, GL_DONT_CARE);
- }
- #endif
- #ifdef SUPPORT_FIXED_FUNCTION
- if (!core_profile) {
- GLint num_red_bits = 0;
- glGetIntegerv(GL_RED_BITS, &num_red_bits);
- if (num_red_bits < 8) {
- glEnable(GL_DITHER);
- _dithering_enabled = true;
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "frame buffer depth = " << num_red_bits
- << " bits/channel, enabling dithering\n";
- }
- }
- }
- #endif
- _error_count = 0;
- report_my_gl_errors();
- #ifndef OPENGLES
- if (_gl_shadlang_ver_major >= 4 || has_extension("GL_NV_gpu_program5")) {
- // gp5fp - OpenGL fragment profile for GeForce 400 Series and up
- _shader_model = SM_50;
- } else if (_gl_shadlang_ver_major >= 3 ||
- has_extension("GL_NV_gpu_program4")) {
- // gp4fp - OpenGL fragment profile for G8x (GeForce 8xxx and up)
- _shader_model = SM_40;
- } else if (has_extension("GL_NV_fragment_program2")) {
- // fp40 - OpenGL fragment profile for NV4x (GeForce 6xxx and 7xxx
- // Series, NV4x-based Quadro FX, etc.)
- _shader_model = SM_30;
- } else if (has_extension("GL_NV_fragment_program")) {
- // fp30 - OpenGL fragment profile for NV3x (GeForce FX, Quadro FX, etc.)
- _shader_model = SM_2X;
- } else if (_gl_shadlang_ver_major >= 1 ||
- has_extension("GL_ARB_fragment_program")) {
- // This OpenGL profile corresponds to the per-fragment
- // functionality introduced by GeForce FX and other DirectX 9 GPUs.
- _shader_model = SM_20;
- } else if (has_extension("GL_NV_texture_shader2")) {
- // fp20 - OpenGL fragment profile for NV2x (GeForce3, GeForce4 Ti,
- // Quadro DCC, etc.)
- _shader_model = SM_11;
- } else {
- // No shader support
- _shader_model = SM_00;
- }
- // DisplayInformation may have better shader model detection
- {
- GraphicsPipe *pipe;
- DisplayInformation *display_information;
- pipe = this->get_pipe();
- if (pipe) {
- display_information = pipe->get_display_information ();
- if (display_information) {
- if (display_information->get_shader_model() > _shader_model) {
- _shader_model = display_information->get_shader_model();
- }
- }
- }
- }
- _auto_detect_shader_model = _shader_model;
- if (GLCAT.is_debug()) {
- #ifdef HAVE_CG
- #if CG_VERSION_NUM >= 2200
- GLCAT.debug() << "Supported Cg profiles:\n";
- int num_profiles = cgGetNumSupportedProfiles();
- for (int i = 0; i < num_profiles; ++i) {
- CGprofile profile = cgGetSupportedProfile(i);
- if (cgGLIsProfileSupported(profile)) {
- GLCAT.debug() << " " << cgGetProfileString(profile) << "\n";
- }
- }
- #endif // CG_VERSION_NUM >= 2200
- #if CG_VERSION_NUM >= 3100
- GLCAT.debug() << "Cg GLSL version = "
- << cgGLGetGLSLVersionString(cgGLDetectGLSLVersion()) << "\n";
- #endif
- GLCAT.debug()
- << "Cg latest vertex profile = "
- << cgGetProfileString(cgGLGetLatestProfile(CG_GL_VERTEX)) << "\n";
- GLCAT.debug()
- << "Cg latest fragment profile = "
- << cgGetProfileString(cgGLGetLatestProfile(CG_GL_FRAGMENT)) << "\n";
- #if CG_VERSION_NUM >= 2000
- GLCAT.debug()
- << "Cg latest geometry profile = "
- << cgGetProfileString(cgGLGetLatestProfile(CG_GL_GEOMETRY)) << "\n";
- #endif
- GLCAT.debug() << "basic-shaders-only " << basic_shaders_only << "\n";
- GLCAT.debug()
- << "Cg active vertex profile = "
- << cgGetProfileString((CGprofile)_shader_caps._active_vprofile) << "\n";
- GLCAT.debug()
- << "Cg active fragment profile = "
- << cgGetProfileString((CGprofile)_shader_caps._active_fprofile) << "\n";
- GLCAT.debug()
- << "Cg active geometry profile = "
- << cgGetProfileString((CGprofile)_shader_caps._active_gprofile) << "\n";
- #endif // HAVE_CG
- GLCAT.debug() << "shader model = " << _shader_model << "\n";
- }
- #endif // !OPENGLES
- // OpenGL core profile requires a VAO to be bound. It's a bit silly,
- // because we can just bind a VAO and then forget about it.
- #if !defined(OPENGLES)
- if (core_profile) {
- if (_supports_vao) {
- _glGenVertexArrays(1, &_current_vao_index);
- _glBindVertexArray(_current_vao_index);
- } else {
- GLCAT.error()
- << "Core profile enabled, but vertex array objects not supported!\n";
- }
- }
- #endif
- // Now that the GSG has been initialized, make it available for
- // optimizations.
- add_gsg(this);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::finish
- // Access: Public, Virtual
- // Description: Force the graphics card to finish drawing before
- // returning. !!!!!HACK WARNING!!!!
- // glfinish does not actually wait for the graphics card to finish drawing
- // only for draw calls to finish. Thus flip may not happene
- // immediately. Instead we read a single pixel from
- // the framebuffer. This forces the graphics card to
- // finish drawing the frame before returning.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- finish() {
- // Rather than call glfinish which returns immediately if
- // draw commands have been submitted, we will read a single pixel
- // from the frame. That will force the graphics card to finish
- // drawing before it is called
- char data[4];
- glReadPixels(0,0,1,1,GL_RGBA,GL_UNSIGNED_BYTE,&data);
- //glFinish();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GraphicsStateGuardian::clear
- // Access: Public
- // Description: Clears the framebuffer within the current
- // DisplayRegion, according to the flags indicated by
- // the given DrawableRegion object.
- //
- // This does not set the DisplayRegion first. You
- // should call prepare_display_region() to specify the
- // region you wish the clear operation to apply to.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- clear(DrawableRegion *clearable) {
- PStatGPUTimer timer(this, _clear_pcollector);
- report_my_gl_errors();
- if (!clearable->is_any_clear_active()) {
- return;
- }
- //XXX rdb: Is this line really necessary?
- set_state_and_transform(RenderState::make_empty(), _internal_transform);
- int mask = 0;
- #ifndef OPENGLES
- if (_current_fbo != 0 && _glClearBufferfv != NULL) {
- // We can use glClearBuffer to clear all the color attachments,
- // which protects us from the overhead of having to call set_draw_buffer
- // for every single attachment.
- int index = 0;
- if (_current_properties->get_color_bits() > 0) {
- if (_current_properties->is_stereo()) {
- // Clear both left and right attachments.
- if (clearable->get_clear_active(GraphicsOutput::RTP_color)) {
- LColorf v = LCAST(float, clearable->get_clear_value(GraphicsOutput::RTP_color));
- _glClearBufferfv(GL_COLOR, index, v.get_data());
- _glClearBufferfv(GL_COLOR, index + 1, v.get_data());
- }
- index += 2;
- } else {
- if (clearable->get_clear_active(GraphicsOutput::RTP_color)) {
- LColorf v = LCAST(float, clearable->get_clear_value(GraphicsOutput::RTP_color));
- _glClearBufferfv(GL_COLOR, index, v.get_data());
- }
- ++index;
- }
- }
- for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
- int layerid = GraphicsOutput::RTP_aux_rgba_0 + i;
- if (clearable->get_clear_active(layerid)) {
- LColorf v = LCAST(float, clearable->get_clear_value(layerid));
- _glClearBufferfv(GL_COLOR, index, v.get_data());
- }
- ++index;
- }
- for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
- int layerid = GraphicsOutput::RTP_aux_hrgba_0 + i;
- if (clearable->get_clear_active(layerid)) {
- LColorf v = LCAST(float, clearable->get_clear_value(layerid));
- _glClearBufferfv(GL_COLOR, index, v.get_data());
- }
- ++index;
- }
- for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
- int layerid = GraphicsOutput::RTP_aux_float_0 + i;
- if (clearable->get_clear_active(layerid)) {
- LColorf v = LCAST(float, clearable->get_clear_value(layerid));
- _glClearBufferfv(GL_COLOR, index, v.get_data());
- }
- ++index;
- }
- } else
- #endif
- {
- if (_current_properties->get_aux_mask() != 0) {
- for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
- int layerid = GraphicsOutput::RTP_aux_rgba_0 + i;
- int layerbit = RenderBuffer::T_aux_rgba_0 << i;
- if (clearable->get_clear_active(layerid)) {
- LColor v = clearable->get_clear_value(layerid);
- glClearColor(v[0], v[1], v[2], v[3]);
- set_draw_buffer(layerbit);
- glClear(GL_COLOR_BUFFER_BIT);
- }
- }
- for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
- int layerid = GraphicsOutput::RTP_aux_hrgba_0 + i;
- int layerbit = RenderBuffer::T_aux_hrgba_0 << i;
- if (clearable->get_clear_active(layerid)) {
- LColor v = clearable->get_clear_value(layerid);
- glClearColor(v[0], v[1], v[2], v[3]);
- set_draw_buffer(layerbit);
- glClear(GL_COLOR_BUFFER_BIT);
- }
- }
- for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
- int layerid = GraphicsOutput::RTP_aux_float_0 + i;
- int layerbit = RenderBuffer::T_aux_float_0 << i;
- if (clearable->get_clear_active(layerid)) {
- LColor v = clearable->get_clear_value(layerid);
- glClearColor(v[0], v[1], v[2], v[3]);
- set_draw_buffer(layerbit);
- glClear(GL_COLOR_BUFFER_BIT);
- }
- }
- // In the past, it was possible to set the draw buffer
- // once in prepare_display_region and then forget about it.
- // Now, with aux layers, it is necessary to occasionally
- // change the draw buffer. In time, I think there will need
- // to be a draw buffer attrib. Until then, this little hack
- // to put things back the way they were after
- // prepare_display_region will do.
- set_draw_buffer(_draw_buffer_type);
- }
- if (_current_properties->get_color_bits() > 0) {
- if (clearable->get_clear_color_active()) {
- LColor v = clearable->get_clear_color();
- glClearColor(v[0], v[1], v[2], v[3]);
- clear_color_write_mask();
- _state_mask.clear_bit(ColorWriteAttrib::get_class_slot());
- mask |= GL_COLOR_BUFFER_BIT;
- }
- }
- }
- if (clearable->get_clear_depth_active()) {
- #ifdef OPENGLES
- glClearDepthf(clearable->get_clear_depth());
- #else
- glClearDepth(clearable->get_clear_depth());
- #endif // OPENGLES
- #ifdef GSG_VERBOSE
- GLCAT.spam()
- << "glDepthMask(GL_TRUE)" << endl;
- #endif
- glDepthMask(GL_TRUE);
- _state_mask.clear_bit(DepthWriteAttrib::get_class_slot());
- mask |= GL_DEPTH_BUFFER_BIT;
- }
- if (clearable->get_clear_stencil_active()) {
- glStencilMask(~0);
- glClearStencil(clearable->get_clear_stencil());
- mask |= GL_STENCIL_BUFFER_BIT;
- }
- glClear(mask);
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "glClear(";
- if (mask & GL_COLOR_BUFFER_BIT) {
- GLCAT.spam(false) << "GL_COLOR_BUFFER_BIT|";
- }
- if (mask & GL_DEPTH_BUFFER_BIT) {
- GLCAT.spam(false) << "GL_DEPTH_BUFFER_BIT|";
- }
- if (mask & GL_STENCIL_BUFFER_BIT) {
- GLCAT.spam(false) << "GL_STENCIL_BUFFER_BIT|";
- }
- #ifndef OPENGLES
- if (mask & GL_ACCUM_BUFFER_BIT) {
- GLCAT.spam(false) << "GL_ACCUM_BUFFER_BIT|";
- }
- #endif
- GLCAT.spam(false) << ")" << endl;
- }
- report_my_gl_errors();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::prepare_display_region
- // Access: Public, Virtual
- // Description: Prepare a display region for rendering (set up
- // scissor region and viewport)
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- prepare_display_region(DisplayRegionPipelineReader *dr) {
- nassertv(dr != (DisplayRegionPipelineReader *)NULL);
- GraphicsStateGuardian::prepare_display_region(dr);
- int l, b, w, h;
- dr->get_region_pixels(l, b, w, h);
- _viewport_x = l;
- _viewport_y = b;
- _viewport_width = w;
- _viewport_height = h;
- GLint x = GLint(l);
- GLint y = GLint(b);
- GLsizei width = GLsizei(w);
- GLsizei height = GLsizei(h);
- _draw_buffer_type = dr->get_object()->get_draw_buffer_type() & _current_properties->get_buffer_mask() & _stereo_buffer_mask;
- _draw_buffer_type |= _current_properties->get_aux_mask();
- set_draw_buffer(_draw_buffer_type);
- int count = dr->get_num_regions();
- if (dr->get_scissor_enabled()) {
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glEnable(GL_SCISSOR_TEST)\n";
- }
- glEnable(GL_SCISSOR_TEST);
- _scissor_enabled = true;
- _scissor_array.resize(count);
- } else {
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glDisable(GL_SCISSOR_TEST)\n";
- }
- glDisable(GL_SCISSOR_TEST);
- _scissor_enabled = false;
- _scissor_array.clear();
- }
- _scissor_attrib_active = false;
- #ifndef OPENGLES
- if (_supports_viewport_arrays) {
- GLfloat *viewports = (GLfloat *)alloca(sizeof(GLfloat) * 4 * count);
- // We store the scissor regions in a vector since we may need
- // to switch back to it in do_issue_scissor.
- for (int i = 0; i < count; ++i) {
- LVecBase4i sr;
- dr->get_region_pixels(i, sr[0], sr[1], sr[2], sr[3]);
- GLfloat *vr = viewports + i * 4;
- vr[0] = (GLfloat) sr[0];
- vr[1] = (GLfloat) sr[1];
- vr[2] = (GLfloat) sr[2];
- vr[3] = (GLfloat) sr[3];
- if (_scissor_enabled) {
- _scissor_array[i] = sr;
- }
- }
- _glViewportArrayv(0, count, viewports);
- if (_scissor_enabled) {
- _glScissorArrayv(0, count, _scissor_array[0].get_data());
- }
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glViewportArrayv(0, " << count << ", [\n";
- for (int i = 0; i < count; ++i) {
- GLfloat *vr = viewports + i * 4;
- GLCAT.spam(false) << vr[0] << ", " << vr[1] << ", " << vr[2] << ", " << vr[3] << ",\n";
- }
- GLCAT.spam(false) << "])\n";
- if (_scissor_enabled) {
- GLCAT.spam()
- << "glScissorArrayv(0, " << count << ", [\n";
- for (int i = 0; i < count; ++i) {
- const LVecBase4i &sr = _scissor_array[i];
- GLCAT.spam(false) << sr << ",\n";
- }
- }
- GLCAT.spam(false) << "])\n";
- }
- } else
- #endif // OPENGLES
- {
- glViewport(x, y, width, height);
- if (_scissor_enabled) {
- glScissor(x, y, width, height);
- _scissor_array.resize(1);
- _scissor_array[0].set(x, y, width, height);
- }
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glViewport(" << x << ", " << y << ", " << width << ", " << height << ")\n";
- if (dr->get_scissor_enabled()) {
- GLCAT.spam()
- << "glScissor(" << x << ", " << y << ", " << width << ", " << height << ")\n";
- }
- }
- }
- report_my_gl_errors();
- do_point_size();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::clear_before_callback
- // Access: Public, Virtual
- // Description: Resets any non-standard graphics state that might
- // give a callback apoplexy. Some drivers require that
- // the graphics state be restored to neutral before
- // performing certain operations. In OpenGL, for
- // instance, this closes any open vertex buffers.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- clear_before_callback() {
- #ifdef SUPPORT_FIXED_FUNCTION
- disable_standard_vertex_arrays();
- #endif
- unbind_buffers();
- // Some callbacks may quite reasonably assume that the active
- // texture stage is still set to stage 0. CEGUI, in particular,
- // makes this assumption.
- _glActiveTexture(GL_TEXTURE0);
- #ifdef SUPPORT_FIXED_FUNCTION
- _glClientActiveTexture(GL_TEXTURE0);
- #endif
- // Clear the bound sampler object, so that we do not inadvertently
- // override the callback's desired sampler settings.
- #ifndef OPENGLES
- if (_supports_sampler_objects) {
- _glBindSampler(0, 0);
- }
- #endif
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::calc_projection_mat
- // Access: Public, Virtual
- // Description: Given a lens, calculates the appropriate projection
- // matrix for use with this gsg. Note that the
- // projection matrix depends a lot upon the coordinate
- // system of the rendering API.
- //
- // The return value is a TransformState if the lens is
- // acceptable, NULL if it is not.
- ////////////////////////////////////////////////////////////////////
- CPT(TransformState) CLP(GraphicsStateGuardian)::
- calc_projection_mat(const Lens *lens) {
- if (lens == (Lens *)NULL) {
- return NULL;
- }
- if (!lens->is_linear()) {
- return NULL;
- }
- // The projection matrix must always be right-handed Y-up, even if
- // our coordinate system of choice is otherwise, because certain GL
- // calls (specifically glTexGen(GL_SPHERE_MAP)) assume this kind of
- // a coordinate system. Sigh. In order to implement a Z-up (or
- // other arbitrary) coordinate system, we'll use a Y-up projection
- // matrix, and store the conversion to our coordinate system of
- // choice in the modelview matrix.
- LMatrix4 result =
- LMatrix4::convert_mat(_internal_coordinate_system,
- lens->get_coordinate_system()) *
- lens->get_projection_mat(_current_stereo_channel);
- if (_scene_setup->get_inverted()) {
- // If the scene is supposed to be inverted, then invert the
- // projection matrix.
- result *= LMatrix4::scale_mat(1.0f, -1.0f, 1.0f);
- }
- return TransformState::make_mat(result);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::prepare_lens
- // Access: Public, Virtual
- // Description: Makes the current lens (whichever lens was most
- // recently specified with set_scene()) active, so
- // that it will transform future rendered geometry.
- // Normally this is only called from the draw process,
- // and usually it is called by set_scene().
- //
- // The return value is true if the lens is acceptable,
- // false if it is not.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- prepare_lens() {
- #ifdef SUPPORT_FIXED_FUNCTION
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glMatrixMode(GL_PROJECTION): " << _projection_mat->get_mat() << endl;
- }
- glMatrixMode(GL_PROJECTION);
- GLPf(LoadMatrix)(_projection_mat->get_mat().get_data());
- report_my_gl_errors();
- do_point_size();
- #endif
- #ifndef OPENGLES_1
- if (_current_shader_context) {
- _current_shader_context->issue_parameters(Shader::SSD_transform);
- }
- #endif
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GraphicsStateGuardian::begin_frame
- // Access: Public, Virtual
- // Description: Called before each frame is rendered, to allow the
- // GSG a chance to do any internal cleanup before
- // beginning the frame.
- //
- // The return value is true if successful (in which case
- // the frame will be drawn and end_frame() will be
- // called later), or false if unsuccessful (in which
- // case nothing will be drawn and end_frame() will not
- // be called).
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- begin_frame(Thread *current_thread) {
- if (!GraphicsStateGuardian::begin_frame(current_thread)) {
- return false;
- }
- _renderbuffer_residency.begin_frame(current_thread);
- report_my_gl_errors();
- #ifdef DO_PSTATS
- _vertices_display_list_pcollector.clear_level();
- _vertices_immediate_pcollector.clear_level();
- _primitive_batches_display_list_pcollector.clear_level();
- #endif
- #ifndef NDEBUG
- _show_texture_usage = false;
- if (gl_show_texture_usage) {
- // When this is true, then every other second, we show the usage
- // textures instead of the real textures.
- double now = ClockObject::get_global_clock()->get_frame_time();
- int this_second = (int)floor(now);
- if (this_second & 1) {
- _show_texture_usage = true;
- _show_texture_usage_index = this_second >> 1;
- int max_size = gl_show_texture_usage_max_size;
- if (max_size != _show_texture_usage_max_size) {
- // Remove the cache of usage textures; we've changed the max
- // size.
- UsageTextures::iterator ui;
- for (ui = _usage_textures.begin();
- ui != _usage_textures.end();
- ++ui) {
- GLuint index = (*ui).second;
- glDeleteTextures(1, &index);
- }
- _usage_textures.clear();
- _show_texture_usage_max_size = max_size;
- }
- }
- }
- #endif // NDEBUG
- #ifdef DO_PSTATS
- /*if (_supports_timer_query) {
- // Measure the difference between the OpenGL clock and the
- // PStats clock.
- GLint64 time_ns;
- _glGetInteger64v(GL_TIMESTAMP, &time_ns);
- _timer_delta = time_ns * -0.000000001;
- _timer_delta += PStatClient::get_global_pstats()->get_real_time();
- }*/
- #endif
- #ifndef OPENGLES
- if (_current_properties->get_srgb_color()) {
- glEnable(GL_FRAMEBUFFER_SRGB);
- }
- #endif
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GraphicsStateGuardian::begin_scene
- // Access: Public, Virtual
- // Description: Called between begin_frame() and end_frame() to mark
- // the beginning of drawing commands for a "scene"
- // (usually a particular DisplayRegion) within a frame.
- // All 3-D drawing commands, except the clear operation,
- // must be enclosed within begin_scene() .. end_scene().
- //
- // The return value is true if successful (in which case
- // the scene will be drawn and end_scene() will be
- // called later), or false if unsuccessful (in which
- // case nothing will be drawn and end_scene() will not
- // be called).
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- begin_scene() {
- return GraphicsStateGuardian::begin_scene();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::end_scene
- // Access: Protected, Virtual
- // Description: Called between begin_frame() and end_frame() to mark
- // the end of drawing commands for a "scene" (usually a
- // particular DisplayRegion) within a frame. All 3-D
- // drawing commands, except the clear operation, must be
- // enclosed within begin_scene() .. end_scene().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- end_scene() {
- GraphicsStateGuardian::end_scene();
- _dlights.clear();
- report_my_gl_errors();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::end_frame
- // Access: Public, Virtual
- // Description: Called after each frame is rendered, to allow the
- // GSG a chance to do any internal cleanup after
- // rendering the frame, and before the window flips.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- end_frame(Thread *current_thread) {
- report_my_gl_errors();
- #ifndef OPENGLES
- if (_current_properties->get_srgb_color()) {
- glDisable(GL_FRAMEBUFFER_SRGB);
- }
- #endif
- #ifdef DO_PSTATS
- // Check for textures, etc., that are no longer resident. These
- // calls might be measurably expensive, and they don't have any
- // benefit unless we are actually viewing PStats, so don't do them
- // unless we're connected. That will just mean that we'll count
- // everything as resident until the user connects PStats, at which
- // point it will then correct the assessment. No harm done.
- if (PStatClient::is_connected()) {
- check_nonresident_texture(_prepared_objects->_texture_residency.get_inactive_resident());
- check_nonresident_texture(_prepared_objects->_texture_residency.get_active_resident());
- // OpenGL provides no methods for querying whether a buffer object
- // (vertex buffer) is resident. In fact, the API appears geared
- // towards the assumption that such buffers are always resident.
- // OK.
- }
- #endif
- #ifndef OPENGLES_1
- // This breaks shaders across multiple regions.
- if (_vertex_array_shader_context != 0) {
- _vertex_array_shader_context->disable_shader_vertex_arrays();
- _vertex_array_shader = (Shader *)NULL;
- _vertex_array_shader_context = (ShaderContext *)NULL;
- }
- if (_texture_binding_shader_context != 0) {
- _texture_binding_shader_context->disable_shader_texture_bindings();
- _texture_binding_shader = (Shader *)NULL;
- _texture_binding_shader_context = (ShaderContext *)NULL;
- }
- if (_current_shader_context != 0) {
- _current_shader_context->unbind();
- _current_shader = (Shader *)NULL;
- _current_shader_context = (ShaderContext *)NULL;
- }
- #endif
- // Calling glFlush() at the end of the frame is particularly
- // necessary if this is a single-buffered visual, so that the frame
- // will be finished drawing before we return to the application.
- // It's not clear what effect this has on our total frame time.
- //if (_force_flush || _current_properties->is_single_buffered()) {
- // gl_flush();
- //}
- maybe_gl_finish();
- GraphicsStateGuardian::end_frame(current_thread);
- _renderbuffer_residency.end_frame(current_thread);
- // Flush any PCollectors specific to this kind of GSG.
- _primitive_batches_display_list_pcollector.flush_level();
- _vertices_display_list_pcollector.flush_level();
- _vertices_immediate_pcollector.flush_level();
- // Now is a good time to delete any pending display lists.
- #ifndef OPENGLES
- #ifdef SUPPORT_FIXED_FUNCTION
- if (display_lists) {
- LightMutexHolder holder(_lock);
- if (!_deleted_display_lists.empty()) {
- DeletedNames::iterator ddli;
- for (ddli = _deleted_display_lists.begin();
- ddli != _deleted_display_lists.end();
- ++ddli) {
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "releasing display list index " << (int)(*ddli) << "\n";
- }
- glDeleteLists((*ddli), 1);
- }
- _deleted_display_lists.clear();
- }
- }
- #endif
- // And deleted queries, too, unless we're using query timers
- // in which case we'll need to reuse lots of them.
- if (_supports_occlusion_query && !get_timer_queries_active()) {
- LightMutexHolder holder(_lock);
- if (!_deleted_queries.empty()) {
- if (GLCAT.is_spam()) {
- DeletedNames::iterator dqi;
- for (dqi = _deleted_queries.begin();
- dqi != _deleted_queries.end();
- ++dqi) {
- GLCAT.spam()
- << "releasing query index " << (int)(*dqi) << "\n";
- }
- }
- _glDeleteQueries(_deleted_queries.size(), &_deleted_queries[0]);
- _deleted_queries.clear();
- }
- }
- #endif // OPENGLES
- #ifndef NDEBUG
- if (_check_errors || (_supports_debug && gl_debug)) {
- report_my_gl_errors();
- } else {
- static int frame_counter = -1;
- // If _check_errors is false, we still want to check for errors
- // the first few frames and once every N frames, so that we know if
- // anything went wrong at all.
- if (frame_counter++ <= 0) {
- PStatTimer timer(_check_error_pcollector);
- GLenum error_code = glGetError();
- if (error_code != GL_NO_ERROR) {
- int error_count = 0;
- bool deactivate = !report_errors_loop(__LINE__, __FILE__, error_code, error_count);
- if (error_count == 1) {
- GLCAT.error()
- << "An OpenGL error (" << get_error_string(error_code)
- << ") has occurred.";
- } else {
- GLCAT.error()
- << error_count << " OpenGL errors have occurred.";
- }
- if (_supports_debug) {
- GLCAT.error(false) << " Set gl-debug #t "
- << "in your PRC file to display more information.\n";
- } else {
- GLCAT.error(false) << " Set gl-check-errors #t "
- << "in your PRC file to display more information.\n";
- }
- if (deactivate) {
- panic_deactivate();
- }
- }
- } else if (frame_counter > 100) {
- // 100 frames have passed. Check next frame.
- frame_counter = 0;
- }
- }
- #endif
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::begin_draw_primitives
- // Access: Public, Virtual
- // Description: Called before a sequence of draw_primitive()
- // functions are called, this should prepare the vertex
- // data for rendering. It returns true if the vertices
- // are ok, false to abort this group of primitives.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- begin_draw_primitives(const GeomPipelineReader *geom_reader,
- const GeomMunger *munger,
- const GeomVertexDataPipelineReader *data_reader,
- bool force) {
- #ifndef NDEBUG
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "begin_draw_primitives: " << *(data_reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- #ifndef SUPPORT_FIXED_FUNCTION
- // We can't draw without a shader bound in OpenGL ES 2. This shouldn't
- // happen anyway unless the default shader failed to compile somehow.
- if (_current_shader_context == NULL) {
- return false;
- }
- #endif
- if (!GraphicsStateGuardian::begin_draw_primitives(geom_reader, munger, data_reader, force)) {
- return false;
- }
- nassertr(_data_reader != (GeomVertexDataPipelineReader *)NULL, false);
- _geom_display_list = 0;
- if (_auto_antialias_mode) {
- switch (geom_reader->get_primitive_type()) {
- case GeomPrimitive::PT_polygons:
- case GeomPrimitive::PT_patches:
- setup_antialias_polygon();
- break;
- case GeomPrimitive::PT_points:
- setup_antialias_point();
- break;
- case GeomPrimitive::PT_lines:
- setup_antialias_line();
- break;
- case GeomPrimitive::PT_none:
- break;
- }
- int transparency_slot = TransparencyAttrib::get_class_slot();
- int color_write_slot = ColorWriteAttrib::get_class_slot();
- int color_blend_slot = ColorBlendAttrib::get_class_slot();
- if (!_state_mask.get_bit(transparency_slot) ||
- !_state_mask.get_bit(color_write_slot) ||
- !_state_mask.get_bit(color_blend_slot)) {
- do_issue_blending();
- _state_mask.set_bit(transparency_slot);
- _state_mask.set_bit(color_write_slot);
- _state_mask.set_bit(color_blend_slot);
- }
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- if (_data_reader->is_vertex_transformed()) {
- // If the vertex data claims to be already transformed into clip
- // coordinates, wipe out the current projection and modelview
- // matrix (so we don't attempt to transform it again).
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- }
- #endif
- #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION) // Display lists not supported by OpenGL ES.
- if (geom_reader->get_usage_hint() == Geom::UH_static &&
- _data_reader->get_usage_hint() == Geom::UH_static &&
- display_lists) {
- // If the geom claims to be totally static, try to build it into
- // a display list.
- // Before we compile or call a display list, make sure the current
- // buffers are unbound, or the nVidia drivers may crash.
- unbind_buffers();
- GeomContext *gc = geom_reader->prepare_now(get_prepared_objects(), this);
- nassertr(gc != (GeomContext *)NULL, false);
- CLP(GeomContext) *ggc = DCAST(CLP(GeomContext), gc);
- const CLP(GeomMunger) *gmunger = DCAST(CLP(GeomMunger), _munger);
- UpdateSeq modified = max(geom_reader->get_modified(), _data_reader->get_modified());
- if (ggc->get_display_list(_geom_display_list, gmunger, modified)) {
- // If it hasn't been modified, just play the display list again.
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "calling display list " << (int)_geom_display_list << "\n";
- }
- glCallList(_geom_display_list);
- #ifdef DO_PSTATS
- _vertices_display_list_pcollector.add_level(ggc->_num_verts);
- _primitive_batches_display_list_pcollector.add_level(1);
- #endif
- // And now we don't need to do anything else for this geom.
- _geom_display_list = 0;
- end_draw_primitives();
- return false;
- }
- // Since we start this collector explicitly, we have to be sure to
- // stop it again.
- _load_display_list_pcollector.start();
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "compiling display list " << (int)_geom_display_list << "\n";
- }
- // If it has been modified, or this is the first time, then we
- // need to build the display list up.
- if (gl_compile_and_execute) {
- glNewList(_geom_display_list, GL_COMPILE_AND_EXECUTE);
- } else {
- glNewList(_geom_display_list, GL_COMPILE);
- }
- #ifdef DO_PSTATS
- // Count up the number of vertices used by primitives in the Geom,
- // for PStats reporting.
- ggc->_num_verts = 0;
- for (int i = 0; i < geom_reader->get_num_primitives(); i++) {
- ggc->_num_verts += geom_reader->get_primitive(i)->get_num_vertices();
- }
- #endif
- }
- #endif // OPENGLES
- // Enable the appropriate vertex arrays, and disable any
- // extra vertex arrays used by the previous rendering mode.
- #ifdef SUPPORT_IMMEDIATE_MODE
- _use_sender = !vertex_arrays;
- #endif
- {
- //PStatGPUTimer timer(this, _vertex_array_update_pcollector);
- #ifdef OPENGLES_1
- if (!update_standard_vertex_arrays(force)) {
- return false;
- }
- #else
- if (_current_shader_context == 0) {
- // No shader.
- if (_vertex_array_shader_context != 0) {
- _vertex_array_shader_context->disable_shader_vertex_arrays();
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- if (!update_standard_vertex_arrays(force)) {
- return false;
- }
- #endif
- } else {
- #ifdef SUPPORT_FIXED_FUNCTION
- // Shader.
- if (_vertex_array_shader_context == 0 || _vertex_array_shader_context->uses_standard_vertex_arrays()) {
- // Previous shader used standard arrays.
- if (_current_shader_context->uses_standard_vertex_arrays()) {
- // So does the current, so update them.
- if (!update_standard_vertex_arrays(force)) {
- return false;
- }
- } else {
- // The current shader does not, so disable them entirely.
- disable_standard_vertex_arrays();
- }
- }
- #endif // SUPPORT_FIXED_FUNCTION
- if (_current_shader_context->uses_custom_vertex_arrays()) {
- // The current shader also uses custom vertex arrays.
- if (!_current_shader_context->
- update_shader_vertex_arrays(_vertex_array_shader_context, force)) {
- return false;
- }
- } else {
- _vertex_array_shader_context->disable_shader_vertex_arrays();
- }
- }
- _vertex_array_shader = _current_shader;
- _vertex_array_shader_context = _current_shader_context;
- #endif // OPENGLES_1
- }
- report_my_gl_errors();
- return true;
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::update_standard_vertex_arrays
- // Access: Protected
- // Description: Disables any unneeded vertex arrays that
- // were previously enabled, and enables any vertex
- // arrays that are needed that were not previously
- // enabled (or, sets up an immediate-mode sender).
- // Called only from begin_draw_primitives.
- // Used only when the standard (non-shader) pipeline
- // is about to be used - glShaderContexts are responsible
- // for setting up their own vertex arrays.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- update_standard_vertex_arrays(bool force) {
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (_use_sender) {
- // We must use immediate mode to render primitives.
- _sender.clear();
- _sender.add_column(_data_reader, InternalName::get_normal(),
- NULL, NULL, GLPf(Normal3), NULL);
- #ifndef NDEBUG
- if (_show_texture_usage) {
- // In show_texture_usage mode, all colors are white, so as not
- // to contaminate the texture color.
- GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f);
- } else
- #endif // NDEBUG
- if (!_sender.add_column(_data_reader, InternalName::get_color(),
- NULL, NULL, GLPf(Color3), GLPf(Color4))) {
- // If we didn't have a color column, the item color is white.
- GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f);
- }
- // Now set up each of the active texture coordinate stages--or at
- // least those for which we're not generating texture coordinates
- // automatically.
- int max_stage_index = _target_texture->get_num_on_ff_stages();
- int stage_index = 0;
- while (stage_index < max_stage_index) {
- TextureStage *stage = _target_texture->get_on_ff_stage(stage_index);
- if (!_target_tex_gen->has_gen_texcoord_stage(stage)) {
- // This stage is not one of the stages that doesn't need
- // texcoords issued for it.
- const InternalName *name = stage->get_texcoord_name();
- if (stage_index == 0) {
- // Use the original functions for stage 0, in case we don't
- // support multitexture.
- _sender.add_column(_data_reader, name,
- GLPf(TexCoord1), GLPf(TexCoord2),
- GLPf(TexCoord3), GLPf(TexCoord4));
- } else {
- // Other stages require the multitexture functions.
- _sender.add_texcoord_column(_data_reader, name, stage_index,
- GLf(_glMultiTexCoord1), GLf(_glMultiTexCoord2),
- GLf(_glMultiTexCoord3), GLf(_glMultiTexCoord4));
- }
- }
- ++stage_index;
- }
- // Be sure also to disable any texture stages we had enabled before.
- while (stage_index < _last_max_stage_index) {
- _glClientActiveTexture(GL_TEXTURE0 + stage_index);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- ++stage_index;
- }
- _last_max_stage_index = max_stage_index;
- // We must add vertex last, because glVertex3f() is the key
- // function call that actually issues the vertex.
- _sender.add_column(_data_reader, InternalName::get_vertex(),
- NULL, GLPf(Vertex2), GLPf(Vertex3), GLPf(Vertex4));
- } else
- #endif // SUPPORT_IMMEDIATE_MODE
- {
- // We may use vertex arrays or buffers to render primitives.
- const GeomVertexArrayDataHandle *array_reader;
- const unsigned char *client_pointer;
- int num_values;
- Geom::NumericType numeric_type;
- int start;
- int stride;
- if (_data_reader->get_normal_info(array_reader, numeric_type,
- start, stride)) {
- if (!setup_array_data(client_pointer, array_reader, force)) {
- return false;
- }
- glNormalPointer(get_numeric_type(numeric_type), stride,
- client_pointer + start);
- glEnableClientState(GL_NORMAL_ARRAY);
- } else {
- glDisableClientState(GL_NORMAL_ARRAY);
- }
- #ifndef NDEBUG
- if (_show_texture_usage) {
- // In show_texture_usage mode, all colors are white, so as not
- // to contaminate the texture color.
- glDisableClientState(GL_COLOR_ARRAY);
- GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f);
- } else
- #endif // NDEBUG
- if (_data_reader->get_color_info(array_reader, num_values, numeric_type,
- start, stride)) {
- if (!setup_array_data(client_pointer, array_reader, force)) {
- return false;
- }
- if (numeric_type == Geom::NT_packed_dabc) {
- glColorPointer(GL_BGRA, GL_UNSIGNED_BYTE,
- stride, client_pointer + start);
- } else {
- glColorPointer(num_values, get_numeric_type(numeric_type),
- stride, client_pointer + start);
- }
- glEnableClientState(GL_COLOR_ARRAY);
- } else {
- glDisableClientState(GL_COLOR_ARRAY);
- // Since we don't have per-vertex color, the implicit color is
- // white.
- GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f);
- }
- // Now set up each of the active texture coordinate stages--or at
- // least those for which we're not generating texture coordinates
- // automatically.
- int max_stage_index = _target_texture->get_num_on_ff_stages();
- int stage_index = 0;
- while (stage_index < max_stage_index) {
- _glClientActiveTexture(GL_TEXTURE0 + stage_index);
- TextureStage *stage = _target_texture->get_on_ff_stage(stage_index);
- if (!_target_tex_gen->has_gen_texcoord_stage(stage)) {
- // This stage is not one of the stages that doesn't need
- // texcoords issued for it.
- const InternalName *name = stage->get_texcoord_name();
- if (_data_reader->get_array_info(name, array_reader, num_values,
- numeric_type, start, stride)) {
- // The vertex data does have texcoords for this stage.
- if (!setup_array_data(client_pointer, array_reader, force)) {
- return false;
- }
- glTexCoordPointer(num_values, get_numeric_type(numeric_type),
- stride, client_pointer + start);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- } else {
- // The vertex data doesn't have texcoords for this stage (even
- // though they're needed).
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
- } else {
- // No texcoords are needed for this stage.
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
- ++stage_index;
- }
- // Be sure also to disable any texture stages we had enabled before.
- while (stage_index < _last_max_stage_index) {
- _glClientActiveTexture(GL_TEXTURE0 + stage_index);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- ++stage_index;
- }
- _last_max_stage_index = max_stage_index;
- // There's no requirement that we add vertices last, but we do
- // anyway.
- if (_data_reader->get_vertex_info(array_reader, num_values, numeric_type,
- start, stride)) {
- if (!setup_array_data(client_pointer, array_reader, force)) {
- return false;
- }
- glVertexPointer(num_values, get_numeric_type(numeric_type),
- stride, client_pointer + start);
- glEnableClientState(GL_VERTEX_ARRAY);
- }
- }
- return true;
- }
- #endif // SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::unbind_buffers
- // Access: Protected
- // Description: Ensures the vertex and array buffers are no longer
- // bound. Some graphics drivers crash if these are left
- // bound indiscriminantly.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- unbind_buffers() {
- if (_current_vbuffer_index != 0) {
- if (GLCAT.is_spam() && gl_debug_buffers) {
- GLCAT.spam()
- << "unbinding vertex buffer\n";
- }
- _glBindBuffer(GL_ARRAY_BUFFER, 0);
- _current_vbuffer_index = 0;
- }
- if (_current_ibuffer_index != 0) {
- if (GLCAT.is_spam() && gl_debug_buffers) {
- GLCAT.spam()
- << "unbinding index buffer\n";
- }
- _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- _current_ibuffer_index = 0;
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- disable_standard_vertex_arrays();
- #endif
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::disable_standard_vertex_arrays
- // Access: Protected
- // Description: Used to disable all the standard vertex arrays that
- // are currently enabled. glShaderContexts are
- // responsible for setting up their own vertex arrays,
- // but before they can do so, the standard vertex
- // arrays need to be disabled to get them "out of the
- // way." Called only from begin_draw_primitives.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- disable_standard_vertex_arrays() {
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (_use_sender) return;
- #endif
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- GLPf(Color4)(1.0f, 1.0f, 1.0f, 1.0f);
- for (int stage_index=0; stage_index < _last_max_stage_index; stage_index++) {
- _glClientActiveTexture(GL_TEXTURE0 + stage_index);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- }
- _last_max_stage_index = 0;
- glDisableClientState(GL_VERTEX_ARRAY);
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::draw_triangles
- // Access: Public, Virtual
- // Description: Draws a series of disconnected triangles.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- draw_triangles(const GeomPrimitivePipelineReader *reader, bool force) {
- //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
- #ifndef NDEBUG
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "draw_triangles: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (_use_sender) {
- draw_immediate_simple_primitives(reader, GL_TRIANGLES);
- } else
- #endif // SUPPORT_IMMEDIATE_MODE
- {
- int num_vertices = reader->get_num_vertices();
- _vertices_tri_pcollector.add_level(num_vertices);
- _primitive_batches_tri_pcollector.add_level(1);
- if (reader->is_indexed()) {
- const unsigned char *client_pointer;
- if (!setup_primitive(client_pointer, reader, force)) {
- return false;
- }
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawElementsInstanced(GL_TRIANGLES, num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer, _instance_count);
- } else
- #endif
- {
- _glDrawRangeElements(GL_TRIANGLES,
- reader->get_min_vertex(),
- reader->get_max_vertex(),
- num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer);
- }
- } else {
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawArraysInstanced(GL_TRIANGLES,
- reader->get_first_vertex(),
- num_vertices, _instance_count);
- } else
- #endif
- {
- glDrawArrays(GL_TRIANGLES,
- reader->get_first_vertex(),
- num_vertices);
- }
- }
- }
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::draw_tristrips
- // Access: Public, Virtual
- // Description: Draws a series of triangle strips.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- draw_tristrips(const GeomPrimitivePipelineReader *reader, bool force) {
- //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
- report_my_gl_errors();
- #ifndef NDEBUG
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "draw_tristrips: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (_use_sender) {
- draw_immediate_composite_primitives(reader, GL_TRIANGLE_STRIP);
- } else
- #endif // SUPPORT_IMMEDIATE_MODE
- {
- if (connect_triangle_strips && _render_mode != RenderModeAttrib::M_wireframe) {
- // One long triangle strip, connected by the degenerate vertices
- // that have already been set up within the primitive.
- int num_vertices = reader->get_num_vertices();
- _vertices_tristrip_pcollector.add_level(num_vertices);
- _primitive_batches_tristrip_pcollector.add_level(1);
- if (reader->is_indexed()) {
- const unsigned char *client_pointer;
- if (!setup_primitive(client_pointer, reader, force)) {
- return false;
- }
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawElementsInstanced(GL_TRIANGLE_STRIP, num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer, _instance_count);
- } else
- #endif
- {
- _glDrawRangeElements(GL_TRIANGLE_STRIP,
- reader->get_min_vertex(),
- reader->get_max_vertex(),
- num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer);
- }
- } else {
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawArraysInstanced(GL_TRIANGLE_STRIP,
- reader->get_first_vertex(),
- num_vertices, _instance_count);
- } else
- #endif
- {
- glDrawArrays(GL_TRIANGLE_STRIP,
- reader->get_first_vertex(),
- num_vertices);
- }
- }
- } else {
- // Send the individual triangle strips, stepping over the
- // degenerate vertices.
- CPTA_int ends = reader->get_ends();
- _primitive_batches_tristrip_pcollector.add_level(ends.size());
- if (reader->is_indexed()) {
- const unsigned char *client_pointer;
- if (!setup_primitive(client_pointer, reader, force)) {
- return false;
- }
- int index_stride = reader->get_index_stride();
- GeomVertexReader mins(reader->get_mins(), 0);
- GeomVertexReader maxs(reader->get_maxs(), 0);
- nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
- reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
- unsigned int start = 0;
- for (size_t i = 0; i < ends.size(); i++) {
- _vertices_tristrip_pcollector.add_level(ends[i] - start);
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawElementsInstanced(GL_TRIANGLE_STRIP, ends[i] - start,
- get_numeric_type(reader->get_index_type()),
- client_pointer + start * index_stride,
- _instance_count);
- } else
- #endif
- {
- _glDrawRangeElements(GL_TRIANGLE_STRIP,
- mins.get_data1i(), maxs.get_data1i(),
- ends[i] - start,
- get_numeric_type(reader->get_index_type()),
- client_pointer + start * index_stride);
- }
- start = ends[i] + 2;
- }
- } else {
- unsigned int start = 0;
- int first_vertex = reader->get_first_vertex();
- for (size_t i = 0; i < ends.size(); i++) {
- _vertices_tristrip_pcollector.add_level(ends[i] - start);
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawArraysInstanced(GL_TRIANGLE_STRIP, first_vertex + start,
- ends[i] - start, _instance_count);
- } else
- #endif
- {
- glDrawArrays(GL_TRIANGLE_STRIP, first_vertex + start,
- ends[i] - start);
- }
- start = ends[i] + 2;
- }
- }
- }
- }
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::draw_trifans
- // Access: Public, Virtual
- // Description: Draws a series of triangle fans.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- draw_trifans(const GeomPrimitivePipelineReader *reader, bool force) {
- //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
- #ifndef NDEBUG
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "draw_trifans: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (_use_sender) {
- draw_immediate_composite_primitives(reader, GL_TRIANGLE_FAN);
- } else
- #endif // SUPPORT_IMMEDIATE_MODE
- {
- // Send the individual triangle fans. There's no connecting fans
- // with degenerate vertices, so no worries about that.
- CPTA_int ends = reader->get_ends();
- _primitive_batches_trifan_pcollector.add_level(ends.size());
- if (reader->is_indexed()) {
- const unsigned char *client_pointer;
- if (!setup_primitive(client_pointer, reader, force)) {
- return false;
- }
- int index_stride = reader->get_index_stride();
- GeomVertexReader mins(reader->get_mins(), 0);
- GeomVertexReader maxs(reader->get_maxs(), 0);
- nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
- reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
- unsigned int start = 0;
- for (size_t i = 0; i < ends.size(); i++) {
- _vertices_trifan_pcollector.add_level(ends[i] - start);
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawElementsInstanced(GL_TRIANGLE_FAN, ends[i] - start,
- get_numeric_type(reader->get_index_type()),
- client_pointer + start * index_stride,
- _instance_count);
- } else
- #endif
- {
- _glDrawRangeElements(GL_TRIANGLE_FAN,
- mins.get_data1i(), maxs.get_data1i(), ends[i] - start,
- get_numeric_type(reader->get_index_type()),
- client_pointer + start * index_stride);
- }
- start = ends[i];
- }
- } else {
- unsigned int start = 0;
- int first_vertex = reader->get_first_vertex();
- for (size_t i = 0; i < ends.size(); i++) {
- _vertices_trifan_pcollector.add_level(ends[i] - start);
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawArraysInstanced(GL_TRIANGLE_FAN, first_vertex + start,
- ends[i] - start, _instance_count);
- } else
- #endif
- {
- glDrawArrays(GL_TRIANGLE_FAN, first_vertex + start,
- ends[i] - start);
- }
- start = ends[i];
- }
- }
- }
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::draw_patches
- // Access: Public, Virtual
- // Description: Draws a series of "patches", which can only be
- // processed by a tessellation shader.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- draw_patches(const GeomPrimitivePipelineReader *reader, bool force) {
- //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
- #ifndef NDEBUG
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "draw_patches: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- if (!get_supports_tessellation_shaders()) {
- return false;
- }
- #ifndef OPENGLES
- _glPatchParameteri(GL_PATCH_VERTICES, reader->get_object()->get_num_vertices_per_primitive());
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (_use_sender) {
- draw_immediate_simple_primitives(reader, GL_PATCHES);
- } else
- #endif // SUPPORT_IMMEDIATE_MODE
- {
- int num_vertices = reader->get_num_vertices();
- _vertices_patch_pcollector.add_level(num_vertices);
- _primitive_batches_patch_pcollector.add_level(1);
- if (reader->is_indexed()) {
- const unsigned char *client_pointer;
- if (!setup_primitive(client_pointer, reader, force)) {
- return false;
- }
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawElementsInstanced(GL_PATCHES, num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer, _instance_count);
- } else
- #endif
- {
- _glDrawRangeElements(GL_PATCHES,
- reader->get_min_vertex(),
- reader->get_max_vertex(),
- num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer);
- }
- } else {
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawArraysInstanced(GL_PATCHES,
- reader->get_first_vertex(),
- num_vertices, _instance_count);
- } else
- #endif
- {
- glDrawArrays(GL_PATCHES,
- reader->get_first_vertex(),
- num_vertices);
- }
- }
- }
- #endif // OPENGLES
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::draw_lines
- // Access: Public, Virtual
- // Description: Draws a series of disconnected line segments.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- draw_lines(const GeomPrimitivePipelineReader *reader, bool force) {
- //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
- #ifndef NDEBUG
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "draw_lines: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (_use_sender) {
- draw_immediate_simple_primitives(reader, GL_LINES);
- } else
- #endif // SUPPORT_IMMEDIATE_MODE
- {
- int num_vertices = reader->get_num_vertices();
- _vertices_other_pcollector.add_level(num_vertices);
- _primitive_batches_other_pcollector.add_level(1);
- if (reader->is_indexed()) {
- const unsigned char *client_pointer;
- if (!setup_primitive(client_pointer, reader, force)) {
- return false;
- }
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawElementsInstanced(GL_LINES, num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer, _instance_count);
- } else
- #endif
- {
- _glDrawRangeElements(GL_LINES,
- reader->get_min_vertex(),
- reader->get_max_vertex(),
- num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer);
- }
- } else {
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawArraysInstanced(GL_LINES,
- reader->get_first_vertex(),
- num_vertices, _instance_count);
- } else
- #endif
- {
- glDrawArrays(GL_LINES,
- reader->get_first_vertex(),
- num_vertices);
- }
- }
- }
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::draw_linestrips
- // Access: Public, Virtual
- // Description: Draws a series of line strips.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- draw_linestrips(const GeomPrimitivePipelineReader *reader, bool force) {
- //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
- report_my_gl_errors();
- #ifndef NDEBUG
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "draw_linestrips: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (_use_sender) {
- draw_immediate_composite_primitives(reader, GL_LINE_STRIP);
- } else
- #endif // SUPPORT_IMMEDIATE_MODE
- {
- if (reader->is_indexed() &&
- (_supported_geom_rendering & GeomEnums::GR_strip_cut_index) != 0) {
- // One long triangle strip, connected by strip cut indices.
- #ifndef OPENGLES
- if (_explicit_primitive_restart) {
- glEnable(GL_PRIMITIVE_RESTART);
- _glPrimitiveRestartIndex(reader->get_strip_cut_index());
- }
- #endif // !OPENGLES
- int num_vertices = reader->get_num_vertices();
- _vertices_other_pcollector.add_level(num_vertices);
- _primitive_batches_other_pcollector.add_level(1);
- const unsigned char *client_pointer;
- if (!setup_primitive(client_pointer, reader, force)) {
- return false;
- }
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawElementsInstanced(GL_LINE_STRIP, num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer, _instance_count);
- } else
- #endif // !OPENGLES
- {
- _glDrawRangeElements(GL_LINE_STRIP,
- reader->get_min_vertex(),
- reader->get_max_vertex(),
- num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer);
- }
- #ifndef OPENGLES
- if (_explicit_primitive_restart) {
- glDisable(GL_PRIMITIVE_RESTART);
- }
- #endif // !OPENGLES
- } else {
- // Send the individual line strips, stepping over the
- // strip-cut indices.
- CPTA_int ends = reader->get_ends();
- _primitive_batches_other_pcollector.add_level(ends.size());
- if (reader->is_indexed()) {
- const unsigned char *client_pointer;
- if (!setup_primitive(client_pointer, reader, force)) {
- return false;
- }
- int index_stride = reader->get_index_stride();
- GeomVertexReader mins(reader->get_mins(), 0);
- GeomVertexReader maxs(reader->get_maxs(), 0);
- nassertr(reader->get_mins()->get_num_rows() == (int)ends.size() &&
- reader->get_maxs()->get_num_rows() == (int)ends.size(), false);
- unsigned int start = 0;
- for (size_t i = 0; i < ends.size(); i++) {
- _vertices_other_pcollector.add_level(ends[i] - start);
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawElementsInstanced(GL_LINE_STRIP, ends[i] - start,
- get_numeric_type(reader->get_index_type()),
- client_pointer + start * index_stride,
- _instance_count);
- } else
- #endif
- {
- _glDrawRangeElements(GL_LINE_STRIP,
- mins.get_data1i(), maxs.get_data1i(),
- ends[i] - start,
- get_numeric_type(reader->get_index_type()),
- client_pointer + start * index_stride);
- }
- start = ends[i] + 1;
- }
- } else {
- unsigned int start = 0;
- int first_vertex = reader->get_first_vertex();
- for (size_t i = 0; i < ends.size(); i++) {
- _vertices_other_pcollector.add_level(ends[i] - start);
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawArraysInstanced(GL_LINE_STRIP, first_vertex + start,
- ends[i] - start, _instance_count);
- } else
- #endif
- {
- glDrawArrays(GL_LINE_STRIP, first_vertex + start, ends[i] - start);
- }
- start = ends[i] + 1;
- }
- }
- }
- }
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::draw_points
- // Access: Public, Virtual
- // Description: Draws a series of disconnected points.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- draw_points(const GeomPrimitivePipelineReader *reader, bool force) {
- //PStatGPUTimer timer(this, _draw_primitive_pcollector, reader->get_current_thread());
- #ifndef NDEBUG
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "draw_points: " << *(reader->get_object()) << "\n";
- }
- #endif // NDEBUG
- #ifdef SUPPORT_IMMEDIATE_MODE
- if (_use_sender) {
- draw_immediate_simple_primitives(reader, GL_POINTS);
- } else
- #endif // SUPPORT_IMMEDIATE_MODE
- {
- int num_vertices = reader->get_num_vertices();
- _vertices_other_pcollector.add_level(num_vertices);
- _primitive_batches_other_pcollector.add_level(1);
- if (reader->is_indexed()) {
- const unsigned char *client_pointer;
- if (!setup_primitive(client_pointer, reader, force)) {
- return false;
- }
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawElementsInstanced(GL_POINTS, num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer, _instance_count);
- } else
- #endif
- {
- _glDrawRangeElements(GL_POINTS,
- reader->get_min_vertex(),
- reader->get_max_vertex(),
- num_vertices,
- get_numeric_type(reader->get_index_type()),
- client_pointer);
- }
- } else {
- #ifndef OPENGLES_1
- if (_supports_geometry_instancing && _instance_count > 0) {
- _glDrawArraysInstanced(GL_POINTS,
- reader->get_first_vertex(),
- num_vertices, _instance_count);
- } else
- #endif
- {
- glDrawArrays(GL_POINTS, reader->get_first_vertex(), num_vertices);
- }
- }
- }
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::end_draw_primitives()
- // Access: Public, Virtual
- // Description: Called after a sequence of draw_primitive()
- // functions are called, this should do whatever cleanup
- // is appropriate.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- end_draw_primitives() {
- #if !defined(OPENGLES) && defined(SUPPORT_FIXED_FUNCTION) // Display lists not supported by OpenGL ES.
- if (_geom_display_list != 0) {
- // If we were building a display list, close it now.
- glEndList();
- _load_display_list_pcollector.stop();
- if (!gl_compile_and_execute) {
- glCallList(_geom_display_list);
- }
- _primitive_batches_display_list_pcollector.add_level(1);
- }
- _geom_display_list = 0;
- #endif
- #ifdef SUPPORT_FIXED_FUNCTION
- if (_transform_stale) {
- glMatrixMode(GL_MODELVIEW);
- GLPf(LoadMatrix)(_internal_transform->get_mat().get_data());
- }
- if (_data_reader->is_vertex_transformed()) {
- // Restore the matrices that we pushed above.
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
- #endif
- GraphicsStateGuardian::end_draw_primitives();
- maybe_gl_finish();
- report_my_gl_errors();
- }
- #ifndef OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::issue_memory_barrier
- // Access: Public
- // Description: Issues the given memory barriers, and clears the
- // list of textures marked as incoherent for the given
- // bits.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- issue_memory_barrier(GLbitfield barriers) {
- if (!gl_enable_memory_barriers || _glMemoryBarrier == NULL) {
- return;
- }
- PStatGPUTimer timer(this, _memory_barrier_pcollector);
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "Issuing memory barriers:";
- }
- _glMemoryBarrier(barriers);
- // Indicate that barriers no longer need to be issued for
- // the relevant lists of textures.
- if (barriers & GL_TEXTURE_FETCH_BARRIER_BIT) {
- _textures_needing_fetch_barrier.clear();
- GLCAT.spam(false) << " texture_fetch";
- }
- if (barriers & GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) {
- _textures_needing_image_access_barrier.clear();
- GLCAT.spam(false) << " shader_image_access";
- }
- if (barriers & GL_TEXTURE_UPDATE_BARRIER_BIT) {
- _textures_needing_update_barrier.clear();
- GLCAT.spam(false) << " texture_update";
- }
- if (barriers & GL_FRAMEBUFFER_BARRIER_BIT) {
- _textures_needing_framebuffer_barrier.clear();
- GLCAT.spam(false) << " framebuffer";
- }
- GLCAT.spam(false) << "\n";
- report_my_gl_errors();
- }
- #endif // OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::prepare_texture
- // Access: Public, Virtual
- // Description: Creates whatever structures the GSG requires to
- // represent the texture internally, and returns a
- // newly-allocated TextureContext object with this data.
- // It is the responsibility of the calling function to
- // later call release_texture() with this same pointer
- // (which will also delete the pointer).
- //
- // This function should not be called directly to
- // prepare a texture. Instead, call Texture::prepare().
- ////////////////////////////////////////////////////////////////////
- TextureContext *CLP(GraphicsStateGuardian)::
- prepare_texture(Texture *tex, int view) {
- PStatGPUTimer timer(this, _prepare_texture_pcollector);
- report_my_gl_errors();
- // Make sure we'll support this texture when it's rendered. Don't
- // bother to prepare it if we won't.
- switch (tex->get_texture_type()) {
- case Texture::TT_3d_texture:
- if (!_supports_3d_texture) {
- GLCAT.warning()
- << "3-D textures are not supported by this OpenGL driver.\n";
- return NULL;
- }
- break;
- case Texture::TT_2d_texture_array:
- if (!_supports_2d_texture_array) {
- GLCAT.warning()
- << "2-D texture arrays are not supported by this OpenGL driver.\n";
- return NULL;
- }
- break;
- case Texture::TT_cube_map:
- if (!_supports_cube_map) {
- GLCAT.warning()
- << "Cube map textures are not supported by this OpenGL driver.\n";
- return NULL;
- }
- break;
- case Texture::TT_buffer_texture:
- if (!_supports_buffer_texture) {
- GLCAT.warning()
- << "Buffer textures are not supported by this OpenGL driver.\n";
- return NULL;
- }
- break;
- default:
- break;
- }
- CLP(TextureContext) *gtc = new CLP(TextureContext)(this, _prepared_objects, tex, view);
- report_my_gl_errors();
- return gtc;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::update_texture
- // Access: Public, Virtual
- // Description: Ensures that the current Texture data is refreshed
- // onto the GSG. This means updating the texture
- // properties and/or re-uploading the texture image, if
- // necessary. This should only be called within the
- // draw thread.
- //
- // If force is true, this function will not return until
- // the texture has been fully uploaded. If force is
- // false, the function may choose to upload a simple
- // version of the texture instead, if the texture is not
- // fully resident (and if get_incomplete_render() is
- // true).
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- update_texture(TextureContext *tc, bool force) {
- CLP(TextureContext) *gtc;
- DCAST_INTO_R(gtc, tc, false);
- if (gtc->was_image_modified() || !gtc->_has_storage) {
- PStatGPUTimer timer(this, _texture_update_pcollector);
- // If the texture image was modified, reload the texture.
- apply_texture(gtc);
- Texture *tex = tc->get_texture();
- if (gtc->was_properties_modified()) {
- specify_texture(gtc, tex->get_default_sampler());
- }
- bool okflag = upload_texture(gtc, force, tex->uses_mipmaps());
- if (!okflag) {
- GLCAT.error()
- << "Could not load " << *tex << "\n";
- return false;
- }
- } else if (gtc->was_properties_modified()) {
- PStatGPUTimer timer(this, _texture_update_pcollector);
- // If only the properties have been modified, we don't necessarily
- // need to reload the texture.
- apply_texture(gtc);
- Texture *tex = tc->get_texture();
- if (specify_texture(gtc, tex->get_default_sampler())) {
- // Actually, looks like the texture *does* need to be reloaded.
- gtc->mark_needs_reload();
- bool okflag = upload_texture(gtc, force, tex->uses_mipmaps());
- if (!okflag) {
- GLCAT.error()
- << "Could not load " << *tex << "\n";
- return false;
- }
- } else {
- // The texture didn't need reloading, but mark it fully updated
- // now.
- gtc->mark_loaded();
- }
- }
- gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::release_texture
- // Access: Public, Virtual
- // Description: Frees the GL resources previously allocated for the
- // texture. This function should never be called
- // directly; instead, call Texture::release() (or simply
- // let the Texture destruct).
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- release_texture(TextureContext *tc) {
- CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
- delete gtc;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::extract_texture_data
- // Access: Public, Virtual
- // Description: This method should only be called by the
- // GraphicsEngine. Do not call it directly; call
- // GraphicsEngine::extract_texture_data() instead.
- //
- // This method will be called in the draw thread to
- // download the texture memory's image into its
- // ram_image value. It returns true on success, false
- // otherwise.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- extract_texture_data(Texture *tex) {
- bool success = true;
- // Make sure the error stack is cleared out before we begin.
- report_my_gl_errors();
- int num_views = tex->get_num_views();
- for (int view = 0; view < num_views; ++view) {
- TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
- nassertr(tc != (TextureContext *)NULL, false);
- CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
- if (!do_extract_texture_data(gtc)) {
- success = false;
- }
- }
- return success;
- }
- #ifndef OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::prepare_sampler
- // Access: Public, Virtual
- // Description: Creates whatever structures the GSG requires to
- // represent the sampler state internally, and returns a
- // newly-allocated SamplerContext object with this data.
- // It is the responsibility of the calling function to
- // later call release_sampler() with this same pointer
- // (which will also delete the pointer).
- //
- // This function should not be called directly to
- // prepare a sampler object. Instead, call
- // SamplerState::prepare().
- ////////////////////////////////////////////////////////////////////
- SamplerContext *CLP(GraphicsStateGuardian)::
- prepare_sampler(const SamplerState &sampler) {
- nassertr(_supports_sampler_objects, NULL);
- PStatGPUTimer timer(this, _prepare_sampler_pcollector);
- CLP(SamplerContext) *gsc = new CLP(SamplerContext)(this, sampler);
- GLuint index = gsc->_index;
- // Sampler contexts are immutable in Panda, so might as well just
- // initialize all the settings here.
- _glSamplerParameteri(index, GL_TEXTURE_WRAP_S,
- get_texture_wrap_mode(sampler.get_wrap_u()));
- _glSamplerParameteri(index, GL_TEXTURE_WRAP_T,
- get_texture_wrap_mode(sampler.get_wrap_v()));
- _glSamplerParameteri(index, GL_TEXTURE_WRAP_R,
- get_texture_wrap_mode(sampler.get_wrap_w()));
- #ifdef STDFLOAT_DOUBLE
- LVecBase4f fvalue = LCAST(float, sampler.get_border_color());
- _glSamplerParameterfv(index, GL_TEXTURE_BORDER_COLOR, fvalue.get_data());
- #else
- _glSamplerParameterfv(index, GL_TEXTURE_BORDER_COLOR,
- sampler.get_border_color().get_data());
- #endif
- SamplerState::FilterType minfilter = sampler.get_effective_minfilter();
- SamplerState::FilterType magfilter = sampler.get_effective_magfilter();
- bool uses_mipmaps = SamplerState::is_mipmap(minfilter) && !gl_ignore_mipmaps;
- #ifndef NDEBUG
- if (gl_force_mipmaps) {
- minfilter = SamplerState::FT_linear_mipmap_linear;
- magfilter = SamplerState::FT_linear;
- uses_mipmaps = true;
- }
- #endif
- _glSamplerParameteri(index, GL_TEXTURE_MIN_FILTER,
- get_texture_filter_type(minfilter, !uses_mipmaps));
- _glSamplerParameteri(index, GL_TEXTURE_MAG_FILTER,
- get_texture_filter_type(magfilter, true));
- // Set anisotropic filtering.
- if (_supports_anisotropy) {
- PN_stdfloat anisotropy = sampler.get_effective_anisotropic_degree();
- anisotropy = min(anisotropy, _max_anisotropy);
- anisotropy = max(anisotropy, (PN_stdfloat)1.0);
- _glSamplerParameterf(index, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
- }
- if (_supports_shadow_filter) {
- if ((sampler.get_magfilter() == SamplerState::FT_shadow) ||
- (sampler.get_minfilter() == SamplerState::FT_shadow)) {
- _glSamplerParameteri(index, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
- _glSamplerParameteri(index, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- } else {
- _glSamplerParameteri(index, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- _glSamplerParameteri(index, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- }
- }
- _glSamplerParameterf(index, GL_TEXTURE_MIN_LOD, sampler.get_min_lod());
- _glSamplerParameterf(index, GL_TEXTURE_MAX_LOD, sampler.get_max_lod());
- _glSamplerParameterf(index, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias());
- gsc->enqueue_lru(&_prepared_objects->_sampler_object_lru);
- report_my_gl_errors();
- return gsc;
- }
- #endif // !OPENGLES
- #ifndef OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::release_sampler
- // Access: Public, Virtual
- // Description: Frees the GL resources previously allocated for the
- // sampler. This function should never be called
- // directly; instead, call SamplerState::release().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- release_sampler(SamplerContext *sc) {
- CLP(SamplerContext) *gsc = DCAST(CLP(SamplerContext), sc);
- delete gsc;
- }
- #endif // !OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::prepare_geom
- // Access: Public, Virtual
- // Description: Creates a new retained-mode representation of the
- // given geom, and returns a newly-allocated
- // GeomContext pointer to reference it. It is the
- // responsibility of the calling function to later
- // call release_geom() with this same pointer (which
- // will also delete the pointer).
- //
- // This function should not be called directly to
- // prepare a geom. Instead, call Geom::prepare().
- ////////////////////////////////////////////////////////////////////
- GeomContext *CLP(GraphicsStateGuardian)::
- prepare_geom(Geom *geom) {
- PStatGPUTimer timer(this, _prepare_geom_pcollector);
- return new CLP(GeomContext)(geom);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::release_geom
- // Access: Public, Virtual
- // Description: Frees the GL resources previously allocated for the
- // geom. This function should never be called
- // directly; instead, call Geom::release() (or simply
- // let the Geom destruct).
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- release_geom(GeomContext *gc) {
- CLP(GeomContext) *ggc = DCAST(CLP(GeomContext), gc);
- ggc->release_display_lists();
- report_my_gl_errors();
- delete ggc;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::prepare_shader
- // Access: Public, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- ShaderContext *CLP(GraphicsStateGuardian)::
- prepare_shader(Shader *se) {
- PStatGPUTimer timer(this, _prepare_shader_pcollector);
- #ifndef OPENGLES_1
- ShaderContext *result = NULL;
- switch (se->get_language()) {
- case Shader::SL_GLSL:
- if (_supports_glsl) {
- result = new CLP(ShaderContext)(this, se);
- break;
- } else {
- GLCAT.error()
- << "Tried to load GLSL shader, but GLSL shaders not supported.\n";
- return NULL;
- }
- case Shader::SL_Cg:
- #if defined(HAVE_CG) && !defined(OPENGLES)
- if (_supports_basic_shaders) {
- result = new CLP(CgShaderContext)(this, se);
- break;
- } else {
- GLCAT.error()
- << "Tried to load Cg shader, but basic shaders not supported.\n";
- return NULL;
- }
- #elif defined(OPENGLES)
- GLCAT.error()
- << "Tried to load Cg shader, but Cg support is not available for OpenGL ES.\n";
- return NULL;
- #else
- GLCAT.error()
- << "Tried to load Cg shader, but Cg support not compiled in.\n";
- return NULL;
- #endif
- default:
- GLCAT.error()
- << "Tried to load shader with unsupported shader language!\n";
- return NULL;
- }
- if (result->valid()) {
- return result;
- }
- delete result;
- #endif // OPENGLES_1
- return NULL;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::release_shader
- // Access: Public, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- release_shader(ShaderContext *sc) {
- delete sc;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::record_deleted_display_list
- // Access: Public
- // Description: This is intended to be called only from the
- // GLGeomContext destructor. It saves the indicated
- // display list index in the list to be deleted at the
- // end of the frame.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- record_deleted_display_list(GLuint index) {
- LightMutexHolder holder(_lock);
- _deleted_display_lists.push_back(index);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::prepare_vertex_buffer
- // Access: Public, Virtual
- // Description: Creates a new retained-mode representation of the
- // given data, and returns a newly-allocated
- // VertexBufferContext pointer to reference it. It is the
- // responsibility of the calling function to later
- // call release_vertex_buffer() with this same pointer (which
- // will also delete the pointer).
- //
- // This function should not be called directly to
- // prepare a buffer. Instead, call Geom::prepare().
- ////////////////////////////////////////////////////////////////////
- VertexBufferContext *CLP(GraphicsStateGuardian)::
- prepare_vertex_buffer(GeomVertexArrayData *data) {
- if (_supports_buffers) {
- PStatGPUTimer timer(this, _prepare_vertex_buffer_pcollector);
- CLP(VertexBufferContext) *gvbc = new CLP(VertexBufferContext)(this, _prepared_objects, data);
- _glGenBuffers(1, &gvbc->_index);
- if (GLCAT.is_debug() && gl_debug_buffers) {
- GLCAT.debug()
- << "creating vertex buffer " << (int)gvbc->_index << ": "
- << data->get_num_rows() << " vertices "
- << *data->get_array_format() << "\n";
- }
- report_my_gl_errors();
- apply_vertex_buffer(gvbc, data->get_handle(), false);
- return gvbc;
- }
- return NULL;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::apply_vertex_buffer
- // Access: Public
- // Description: Makes the data the currently available data for
- // rendering.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- apply_vertex_buffer(VertexBufferContext *vbc,
- const GeomVertexArrayDataHandle *reader, bool force) {
- nassertr(_supports_buffers, false);
- if (reader->get_modified() == UpdateSeq::initial()) {
- // No need to re-apply.
- return true;
- }
- CLP(VertexBufferContext) *gvbc = DCAST(CLP(VertexBufferContext), vbc);
- if (_current_vbuffer_index != gvbc->_index) {
- if (GLCAT.is_spam() && gl_debug_buffers) {
- GLCAT.spam()
- << "binding vertex buffer " << (int)gvbc->_index << "\n";
- }
- _glBindBuffer(GL_ARRAY_BUFFER, gvbc->_index);
- _current_vbuffer_index = gvbc->_index;
- gvbc->set_active(true);
- }
- if (gvbc->was_modified(reader)) {
- int num_bytes = reader->get_data_size_bytes();
- if (GLCAT.is_debug() && gl_debug_buffers) {
- GLCAT.debug()
- << "copying " << num_bytes
- << " bytes into vertex buffer " << (int)gvbc->_index << "\n";
- }
- if (num_bytes != 0) {
- const unsigned char *client_pointer = reader->get_read_pointer(force);
- if (client_pointer == NULL) {
- return false;
- }
- PStatGPUTimer timer(this, _load_vertex_buffer_pcollector, reader->get_current_thread());
- if (gvbc->changed_size(reader) || gvbc->changed_usage_hint(reader)) {
- _glBufferData(GL_ARRAY_BUFFER, num_bytes, client_pointer,
- get_usage(reader->get_usage_hint()));
- } else {
- _glBufferSubData(GL_ARRAY_BUFFER, 0, num_bytes, client_pointer);
- }
- _data_transferred_pcollector.add_level(num_bytes);
- }
- gvbc->mark_loaded(reader);
- }
- gvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
- maybe_gl_finish();
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::release_vertex_buffer
- // Access: Public, Virtual
- // Description: Frees the GL resources previously allocated for the
- // data. This function should never be called
- // directly; instead, call Data::release() (or simply
- // let the Data destruct).
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- release_vertex_buffer(VertexBufferContext *vbc) {
- nassertv(_supports_buffers);
- CLP(VertexBufferContext) *gvbc = DCAST(CLP(VertexBufferContext), vbc);
- if (GLCAT.is_debug() && gl_debug_buffers) {
- GLCAT.debug()
- << "deleting vertex buffer " << (int)gvbc->_index << "\n";
- }
- // Make sure the buffer is unbound before we delete it. Not
- // strictly necessary according to the OpenGL spec, but it might
- // help out a flaky driver, and we need to keep our internal state
- // consistent anyway.
- if (_current_vbuffer_index == gvbc->_index) {
- if (GLCAT.is_spam() && gl_debug_buffers) {
- GLCAT.spam()
- << "unbinding vertex buffer\n";
- }
- _glBindBuffer(GL_ARRAY_BUFFER, 0);
- _current_vbuffer_index = 0;
- }
- _glDeleteBuffers(1, &gvbc->_index);
- report_my_gl_errors();
- gvbc->_index = 0;
- delete gvbc;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::setup_array_data
- // Access: Public
- // Description: Internal function to bind a buffer object for the
- // indicated data array, if appropriate, or to unbind a
- // buffer object if it should be rendered from client
- // memory.
- //
- // If the buffer object is bound, this function sets
- // client_pointer to NULL (representing the start of the
- // buffer object in server memory); if the buffer object
- // is not bound, this function sets client_pointer the
- // pointer to the data array in client memory, that is,
- // the data array passed in.
- //
- // If force is not true, the function may return false
- // indicating the data is not currently available.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- setup_array_data(const unsigned char *&client_pointer,
- const GeomVertexArrayDataHandle *array_reader,
- bool force) {
- if (!_supports_buffers) {
- // No support for buffer objects; always render from client.
- client_pointer = array_reader->get_read_pointer(force);
- return (client_pointer != NULL);
- }
- if (!vertex_buffers || _geom_display_list != 0 ||
- array_reader->get_usage_hint() < gl_min_buffer_usage_hint) {
- // The array specifies client rendering only, or buffer objects
- // are configured off.
- if (_current_vbuffer_index != 0) {
- if (GLCAT.is_spam() && gl_debug_buffers) {
- GLCAT.spam()
- << "unbinding vertex buffer\n";
- }
- _glBindBuffer(GL_ARRAY_BUFFER, 0);
- _current_vbuffer_index = 0;
- }
- client_pointer = array_reader->get_read_pointer(force);
- return (client_pointer != NULL);
- }
- // Prepare the buffer object and bind it.
- VertexBufferContext *vbc = array_reader->prepare_now(get_prepared_objects(), this);
- nassertr(vbc != (VertexBufferContext *)NULL, false);
- if (!apply_vertex_buffer(vbc, array_reader, force)) {
- return false;
- }
- // NULL is the OpenGL convention for the first byte of the buffer object.
- client_pointer = NULL;
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::prepare_index_buffer
- // Access: Public, Virtual
- // Description: Creates a new retained-mode representation of the
- // given data, and returns a newly-allocated
- // IndexBufferContext pointer to reference it. It is the
- // responsibility of the calling function to later
- // call release_index_buffer() with this same pointer (which
- // will also delete the pointer).
- //
- // This function should not be called directly to
- // prepare a buffer. Instead, call Geom::prepare().
- ////////////////////////////////////////////////////////////////////
- IndexBufferContext *CLP(GraphicsStateGuardian)::
- prepare_index_buffer(GeomPrimitive *data) {
- if (_supports_buffers) {
- PStatGPUTimer timer(this, _prepare_index_buffer_pcollector);
- CLP(IndexBufferContext) *gibc = new CLP(IndexBufferContext)(this, _prepared_objects, data);
- _glGenBuffers(1, &gibc->_index);
- if (GLCAT.is_debug() && gl_debug_buffers) {
- GLCAT.debug()
- << "creating index buffer " << (int)gibc->_index << ": "
- << data->get_num_vertices() << " indices ("
- << data->get_vertices()->get_array_format()->get_column(0)->get_numeric_type()
- << ")\n";
- }
- report_my_gl_errors();
- GeomPrimitivePipelineReader reader(data, Thread::get_current_thread());
- apply_index_buffer(gibc, &reader, false);
- return gibc;
- }
- return NULL;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::apply_index_buffer
- // Access: Public
- // Description: Makes the data the currently available data for
- // rendering.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- apply_index_buffer(IndexBufferContext *ibc,
- const GeomPrimitivePipelineReader *reader,
- bool force) {
- nassertr(_supports_buffers, false);
- if (reader->get_modified() == UpdateSeq::initial()) {
- // No need to re-apply.
- return true;
- }
- CLP(IndexBufferContext) *gibc = DCAST(CLP(IndexBufferContext), ibc);
- if (_current_ibuffer_index != gibc->_index) {
- if (GLCAT.is_spam() && gl_debug_buffers) {
- GLCAT.spam()
- << "binding index buffer " << (int)gibc->_index << "\n";
- }
- _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, gibc->_index);
- _current_ibuffer_index = gibc->_index;
- gibc->set_active(true);
- }
- if (gibc->was_modified(reader)) {
- int num_bytes = reader->get_data_size_bytes();
- if (GLCAT.is_debug() && gl_debug_buffers) {
- GLCAT.debug()
- << "copying " << num_bytes
- << " bytes into index buffer " << (int)gibc->_index << "\n";
- }
- if (num_bytes != 0) {
- const unsigned char *client_pointer = reader->get_read_pointer(force);
- if (client_pointer == NULL) {
- return false;
- }
- PStatGPUTimer timer(this, _load_index_buffer_pcollector, reader->get_current_thread());
- if (gibc->changed_size(reader) || gibc->changed_usage_hint(reader)) {
- _glBufferData(GL_ELEMENT_ARRAY_BUFFER, num_bytes, client_pointer,
- get_usage(reader->get_usage_hint()));
- } else {
- _glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, num_bytes,
- client_pointer);
- }
- _data_transferred_pcollector.add_level(num_bytes);
- }
- gibc->mark_loaded(reader);
- }
- gibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
- maybe_gl_finish();
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::release_index_buffer
- // Access: Public, Virtual
- // Description: Frees the GL resources previously allocated for the
- // data. This function should never be called
- // directly; instead, call Data::release() (or simply
- // let the Data destruct).
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- release_index_buffer(IndexBufferContext *ibc) {
- nassertv(_supports_buffers);
- CLP(IndexBufferContext) *gibc = DCAST(CLP(IndexBufferContext), ibc);
- if (GLCAT.is_debug() && gl_debug_buffers) {
- GLCAT.debug()
- << "deleting index buffer " << (int)gibc->_index << "\n";
- }
- // Make sure the buffer is unbound before we delete it. Not
- // strictly necessary according to the OpenGL spec, but it might
- // help out a flaky driver, and we need to keep our internal state
- // consistent anyway.
- if (_current_ibuffer_index == gibc->_index) {
- if (GLCAT.is_spam() && gl_debug_buffers) {
- GLCAT.spam()
- << "unbinding index buffer\n";
- }
- _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- _current_ibuffer_index = 0;
- }
- _glDeleteBuffers(1, &gibc->_index);
- report_my_gl_errors();
- gibc->_index = 0;
- delete gibc;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::setup_primitive
- // Access: Public
- // Description: Internal function to bind a buffer object for the
- // indicated primitive's index list, if appropriate, or
- // to unbind a buffer object if it should be rendered
- // from client memory.
- //
- // If the buffer object is bound, this function sets
- // client_pointer to NULL (representing the start of the
- // buffer object in server memory); if the buffer object
- // is not bound, this function sets client_pointer to to
- // the data array in client memory, that is, the data
- // array passed in.
- //
- // If force is not true, the function may return false
- // indicating the data is not currently available.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- setup_primitive(const unsigned char *&client_pointer,
- const GeomPrimitivePipelineReader *reader,
- bool force) {
- if (!_supports_buffers) {
- // No support for buffer objects; always render from client.
- client_pointer = reader->get_read_pointer(force);
- return (client_pointer != NULL);
- }
- if (!vertex_buffers || _geom_display_list != 0 ||
- reader->get_usage_hint() == Geom::UH_client) {
- // The array specifies client rendering only, or buffer objects
- // are configured off.
- if (_current_ibuffer_index != 0) {
- if (GLCAT.is_spam() && gl_debug_buffers) {
- GLCAT.spam()
- << "unbinding index buffer\n";
- }
- _glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
- _current_ibuffer_index = 0;
- }
- client_pointer = reader->get_read_pointer(force);
- return (client_pointer != NULL);
- }
- // Prepare the buffer object and bind it.
- IndexBufferContext *ibc = reader->prepare_now(get_prepared_objects(), this);
- nassertr(ibc != (IndexBufferContext *)NULL, false);
- if (!apply_index_buffer(ibc, reader, force)) {
- return false;
- }
- // NULL is the OpenGL convention for the first byte of the buffer object.
- client_pointer = NULL;
- return true;
- }
- #ifndef OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::begin_occlusion_query
- // Access: Public, Virtual
- // Description: Begins a new occlusion query. After this call, you
- // may call begin_draw_primitives() and
- // draw_triangles()/draw_whatever() repeatedly.
- // Eventually, you should call end_occlusion_query()
- // before the end of the frame; that will return a new
- // OcclusionQueryContext object that will tell you how
- // many pixels represented by the bracketed geometry
- // passed the depth test.
- //
- // It is not valid to call begin_occlusion_query()
- // between another begin_occlusion_query()
- // .. end_occlusion_query() sequence.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- begin_occlusion_query() {
- nassertv(_supports_occlusion_query);
- nassertv(_current_occlusion_query == (OcclusionQueryContext *)NULL);
- PT(CLP(OcclusionQueryContext)) query = new CLP(OcclusionQueryContext)(this);
- _glGenQueries(1, &query->_index);
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "beginning occlusion query index " << (int)query->_index << "\n";
- }
- _glBeginQuery(GL_SAMPLES_PASSED, query->_index);
- _current_occlusion_query = query;
- report_my_gl_errors();
- }
- #endif // !OPENGLES
- #ifndef OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::end_occlusion_query
- // Access: Public, Virtual
- // Description: Ends a previous call to begin_occlusion_query().
- // This call returns the OcclusionQueryContext object
- // that will (eventually) report the number of pixels
- // that passed the depth test between the call to
- // begin_occlusion_query() and end_occlusion_query().
- ////////////////////////////////////////////////////////////////////
- PT(OcclusionQueryContext) CLP(GraphicsStateGuardian)::
- end_occlusion_query() {
- nassertr(_current_occlusion_query != (OcclusionQueryContext *)NULL, NULL);
- PT(OcclusionQueryContext) result = _current_occlusion_query;
- GLuint index = DCAST(CLP(OcclusionQueryContext), result)->_index;
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "ending occlusion query index " << (int)index << "\n";
- }
- _current_occlusion_query = NULL;
- _glEndQuery(GL_SAMPLES_PASSED);
- // Temporary hack to try working around an apparent driver bug on
- // iMacs. Occlusion queries sometimes incorrectly report 0 samples,
- // unless we stall the pipe to keep fewer than a certain maximum
- // number of queries pending at once.
- static ConfigVariableInt limit_occlusion_queries("limit-occlusion-queries", 0);
- if (limit_occlusion_queries > 0) {
- if (index > (unsigned int)limit_occlusion_queries) {
- PStatGPUTimer timer(this, _wait_occlusion_pcollector);
- GLuint result;
- _glGetQueryObjectuiv(index - (unsigned int)limit_occlusion_queries,
- GL_QUERY_RESULT, &result);
- }
- }
- report_my_gl_errors();
- return result;
- }
- #endif // !OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::issue_timer_query
- // Access: Public, Virtual
- // Description: Adds a timer query to the command stream, associated
- // with the given PStats collector index.
- ////////////////////////////////////////////////////////////////////
- PT(TimerQueryContext) CLP(GraphicsStateGuardian)::
- issue_timer_query(int pstats_index) {
- #if defined(DO_PSTATS) && !defined(OPENGLES)
- nassertr(_supports_timer_query, NULL);
- PT(CLP(TimerQueryContext)) query;
- // Hack
- if (pstats_index == _command_latency_pcollector.get_index()) {
- query = new CLP(LatencyQueryContext)(this, pstats_index);
- } else {
- query = new CLP(TimerQueryContext)(this, pstats_index);
- }
- if (_deleted_queries.size() >= 1) {
- query->_index = _deleted_queries.back();
- _deleted_queries.pop_back();
- } else {
- _glGenQueries(1, &query->_index);
- if (GLCAT.is_spam()) {
- GLCAT.spam() << "Generating query for " << pstats_index
- << ": " << query->_index << "\n";
- }
- }
- // Issue the timestamp query.
- _glQueryCounter(query->_index, GL_TIMESTAMP);
- if (_use_object_labels) {
- // Assign a label to it based on the PStatCollector name.
- const PStatClient *client = PStatClient::get_global_pstats();
- string name = client->get_collector_fullname(pstats_index & 0x7fff);
- _glObjectLabel(GL_QUERY, query->_index, name.size(), name.data());
- }
- _pending_timer_queries.push_back((TimerQueryContext *)query);
- return (TimerQueryContext *)query;
- #else
- return NULL;
- #endif
- }
- #ifndef OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::dispatch_compute
- // Access: Public, Virtual
- // Description: Dispatches a currently bound compute shader using
- // the given work group counts.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- dispatch_compute(int num_groups_x, int num_groups_y, int num_groups_z) {
- maybe_gl_finish();
- PStatGPUTimer timer(this, _compute_dispatch_pcollector);
- nassertv(_supports_compute_shaders);
- nassertv(_current_shader_context != NULL);
- _glDispatchCompute(num_groups_x, num_groups_y, num_groups_z);
- maybe_gl_finish();
- }
- #endif // !OPENGLES
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::make_geom_munger
- // Access: Public, Virtual
- // Description: Creates a new GeomMunger object to munge vertices
- // appropriate to this GSG for the indicated state.
- ////////////////////////////////////////////////////////////////////
- PT(GeomMunger) CLP(GraphicsStateGuardian)::
- make_geom_munger(const RenderState *state, Thread *current_thread) {
- PT(CLP(GeomMunger)) munger = new CLP(GeomMunger)(this, state);
- return GeomMunger::register_munger(munger, current_thread);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::compute_distance_to
- // Access: Public, Virtual
- // Description: This function will compute the distance to the
- // indicated point, assumed to be in eye coordinates,
- // from the camera plane. The point is assumed to be
- // in the GSG's internal coordinate system.
- ////////////////////////////////////////////////////////////////////
- PN_stdfloat CLP(GraphicsStateGuardian)::
- compute_distance_to(const LPoint3 &point) const {
- return -point[2];
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::framebuffer_copy_to_texture
- // Access: Public, Virtual
- // Description: Copy the pixels within the indicated display
- // region from the framebuffer into texture memory.
- //
- // If z > -1, it is the cube map index or layer index
- // into which to copy.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- framebuffer_copy_to_texture(Texture *tex, int view, int z,
- const DisplayRegion *dr, const RenderBuffer &rb) {
- nassertr(tex != NULL && dr != NULL, false);
- set_read_buffer(rb._buffer_type);
- clear_color_write_mask();
- int xo, yo, w, h;
- dr->get_region_pixels(xo, yo, w, h);
- tex->set_size_padded(w, h, tex->get_z_size());
- if (tex->get_compression() == Texture::CM_default) {
- // Unless the user explicitly turned on texture compression, turn
- // it off for the copy-to-texture case.
- tex->set_compression(Texture::CM_off);
- }
- // Sanity check everything.
- if (z >= 0) {
- if (z >= tex->get_z_size()) {
- // This can happen, when textures with different layer counts
- // are attached to a buffer. We simply ignore this if it happens.
- return false;
- }
- if ((w != tex->get_x_size()) ||
- (h != tex->get_y_size())) {
- return false;
- }
- if (tex->get_texture_type() == Texture::TT_cube_map) {
- if (!_supports_cube_map) {
- return false;
- }
- nassertr(z < 6, false);
- if (w != h) {
- return false;
- }
- } else if (tex->get_texture_type() == Texture::TT_3d_texture) {
- if (!_supports_3d_texture) {
- return false;
- }
- } else if (tex->get_texture_type() == Texture::TT_2d_texture_array) {
- if (!_supports_2d_texture_array) {
- return false;
- }
- } else {
- GLCAT.error()
- << "Don't know how to copy framebuffer to texture " << *tex << "\n";
- }
- } else {
- nassertr(tex->get_texture_type() == Texture::TT_2d_texture, false);
- }
- // Match framebuffer format if necessary.
- if (tex->get_match_framebuffer_format()) {
- switch (tex->get_format()) {
- case Texture::F_depth_component:
- case Texture::F_depth_component16:
- case Texture::F_depth_component24:
- case Texture::F_depth_component32:
- case Texture::F_depth_stencil:
- // Don't remap if we're one of these special format.
- break;
- default:
- // If the texture is a color format, we want to match the
- // presence of sRGB and alpha according to the framebuffer.
- if (_current_properties->get_srgb_color()) {
- if (_current_properties->get_alpha_bits()) {
- tex->set_format(Texture::F_srgb_alpha);
- } else {
- tex->set_format(Texture::F_srgb);
- }
- } else {
- if (_current_properties->get_alpha_bits()) {
- tex->set_format(Texture::F_rgba);
- } else {
- tex->set_format(Texture::F_rgb);
- }
- }
- }
- }
- TextureContext *tc = tex->prepare_now(view, get_prepared_objects(), this);
- nassertr(tc != (TextureContext *)NULL, false);
- CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
- apply_texture(gtc);
- bool needs_reload = specify_texture(gtc, tex->get_default_sampler());
- GLenum target = get_texture_target(tex->get_texture_type());
- GLint internal_format = get_internal_image_format(tex);
- int width = tex->get_x_size();
- int height = tex->get_y_size();
- int depth = tex->get_z_size();
- bool uses_mipmaps = tex->uses_mipmaps() && !gl_ignore_mipmaps;
- if (uses_mipmaps) {
- if (_supports_generate_mipmap) {
- #ifndef OPENGLES_2
- if (_glGenerateMipmap == NULL) {
- glTexParameteri(target, GL_GENERATE_MIPMAP, true);
- }
- #endif
- } else {
- // If we can't auto-generate mipmaps, do without mipmaps.
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- uses_mipmaps = false;
- }
- }
- bool new_image = needs_reload || gtc->was_image_modified();
- if (z >= 0) {
- if (target == GL_TEXTURE_CUBE_MAP) {
- // Copy to a cube map face, which is treated as a 2D texture.
- target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z;
- depth = 1;
- z = -1;
- // Cube map faces seem to have trouble with CopyTexSubImage, so we
- // always reload the image.
- new_image = true;
- }
- }
- if (!gtc->_has_storage ||
- internal_format != gtc->_internal_format ||
- uses_mipmaps != gtc->_uses_mipmaps ||
- width != gtc->_width ||
- height != gtc->_height ||
- depth != gtc->_depth) {
- // If the texture properties have changed, we need to reload the
- // image.
- new_image = true;
- }
- if (new_image && gtc->_immutable) {
- gtc->reset_data();
- glBindTexture(target, gtc->_index);
- }
- #ifndef OPENGLES
- if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT)) {
- // Make sure that any incoherent writes to this texture have been synced.
- issue_memory_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
- }
- #endif
- if (z >= 0) {
- #ifndef OPENGLES_1
- if (new_image) {
- // These won't be used because we pass a NULL image, but we still
- // have to specify them. Might as well use the actual values.
- GLint external_format = get_external_image_format(tex);
- GLint component_type = get_component_type(tex->get_component_type());
- _glTexImage3D(target, 0, internal_format, width, height, depth, 0, external_format, component_type, NULL);
- }
- _glCopyTexSubImage3D(target, 0, 0, 0, z, xo, yo, w, h);
- #endif
- } else {
- if (new_image) {
- // We have to create a new image.
- // It seems that OpenGL accepts a size higher than the framebuffer,
- // but if we run into trouble we'll have to replace this with
- // something smarter.
- glCopyTexImage2D(target, 0, internal_format, xo, yo, width, height, 0);
- } else {
- // We can overlay the existing image.
- glCopyTexSubImage2D(target, 0, 0, 0, xo, yo, w, h);
- }
- }
- if (uses_mipmaps && _glGenerateMipmap != NULL) {
- glEnable(target);
- _glGenerateMipmap(target);
- glDisable(target);
- }
- gtc->_has_storage = true;
- gtc->_uses_mipmaps = uses_mipmaps;
- gtc->_internal_format = internal_format;
- gtc->_width = width;
- gtc->_height = height;
- gtc->_depth = depth;
- gtc->mark_loaded();
- gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
- report_my_gl_errors();
- // Force reload of texture state, since we've just monkeyed with it.
- _state_mask.clear_bit(TextureAttrib::get_class_slot());
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::framebuffer_copy_to_ram
- // Access: Public, Virtual
- // Description: Copy the pixels within the indicated display region
- // from the framebuffer into system memory, not texture
- // memory. Returns true on success, false on failure.
- //
- // This completely redefines the ram image of the
- // indicated texture.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- framebuffer_copy_to_ram(Texture *tex, int view, int z,
- const DisplayRegion *dr, const RenderBuffer &rb) {
- nassertr(tex != NULL && dr != NULL, false);
- set_read_buffer(rb._buffer_type);
- glPixelStorei(GL_PACK_ALIGNMENT, 1);
- clear_color_write_mask();
- // Bug fix for RE, RE2, and VTX - need to disable texturing in order
- // for glReadPixels() to work
- // NOTE: reading the depth buffer is *much* slower than reading the
- // color buffer
- set_state_and_transform(RenderState::make_empty(), _internal_transform);
- int xo, yo, w, h;
- dr->get_region_pixels(xo, yo, w, h);
- Texture::ComponentType component_type = tex->get_component_type();
- bool color_mode = false;
- Texture::Format format = tex->get_format();
- switch (format) {
- case Texture::F_depth_stencil:
- if (_current_properties->get_float_depth()) {
- component_type = Texture::T_float;
- } else {
- component_type = Texture::T_unsigned_int_24_8;
- }
- break;
- case Texture::F_depth_component:
- if (_current_properties->get_float_depth()) {
- component_type = Texture::T_float;
- } else if (_current_properties->get_depth_bits() <= 8) {
- component_type = Texture::T_unsigned_byte;
- } else if (_current_properties->get_depth_bits() <= 16) {
- component_type = Texture::T_unsigned_short;
- } else {
- component_type = Texture::T_float;
- }
- break;
- default:
- color_mode = true;
- if (_current_properties->get_srgb_color()) {
- if (_current_properties->get_alpha_bits()) {
- format = Texture::F_srgb_alpha;
- } else {
- format = Texture::F_srgb;
- }
- } else {
- if (_current_properties->get_alpha_bits()) {
- format = Texture::F_rgba;
- } else {
- format = Texture::F_rgb;
- }
- }
- if (_current_properties->get_float_color()) {
- component_type = Texture::T_float;
- } else if (_current_properties->get_color_bits() <= 24) {
- component_type = Texture::T_unsigned_byte;
- } else {
- component_type = Texture::T_unsigned_short;
- }
- }
- Texture::TextureType texture_type;
- int z_size;
- //TODO: should be extended to support 3D textures and 2D arrays.
- if (z >= 0) {
- texture_type = Texture::TT_cube_map;
- z_size = 6;
- } else {
- texture_type = Texture::TT_2d_texture;
- z_size = 1;
- }
- if (tex->get_x_size() != w || tex->get_y_size() != h ||
- tex->get_z_size() != z_size ||
- tex->get_component_type() != component_type ||
- tex->get_format() != format ||
- tex->get_texture_type() != texture_type) {
- // Re-setup the texture; its properties have changed.
- tex->setup_texture(texture_type, w, h, z_size,
- component_type, format);
- }
- nassertr(z < tex->get_z_size(), false);
- GLenum external_format = get_external_image_format(tex);
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glReadPixels(" << xo << ", " << yo << ", " << w << ", " << h << ", ";
- switch (external_format) {
- case GL_DEPTH_COMPONENT:
- GLCAT.spam(false) << "GL_DEPTH_COMPONENT, ";
- break;
- case GL_DEPTH_STENCIL:
- GLCAT.spam(false) << "GL_DEPTH_STENCIL, ";
- break;
- case GL_RGB:
- GLCAT.spam(false) << "GL_RGB, ";
- break;
- case GL_RGBA:
- GLCAT.spam(false) << "GL_RGBA, ";
- break;
- #ifndef OPENGLES
- case GL_BGR:
- GLCAT.spam(false) << "GL_BGR, ";
- break;
- #endif
- case GL_BGRA:
- GLCAT.spam(false) << "GL_BGRA, ";
- break;
- default:
- GLCAT.spam(false) << "unknown, ";
- break;
- }
- switch (get_component_type(component_type)) {
- case GL_UNSIGNED_BYTE:
- GLCAT.spam(false) << "GL_UNSIGNED_BYTE";
- break;
- case GL_UNSIGNED_SHORT:
- GLCAT.spam(false) << "GL_UNSIGNED_SHORT";
- break;
- case GL_FLOAT:
- GLCAT.spam(false) << "GL_FLOAT";
- break;
- #ifndef OPENGLES_1
- case GL_INT:
- GLCAT.spam(false) << "GL_INT";
- break;
- #endif
- default:
- GLCAT.spam(false) << "unknown";
- break;
- }
- GLCAT.spam(false)
- << ")" << endl;
- }
- unsigned char *image_ptr = tex->modify_ram_image();
- size_t image_size = tex->get_ram_image_size();
- if (z >= 0 || view > 0) {
- image_size = tex->get_expected_ram_page_size();
- if (z >= 0) {
- image_ptr += z * image_size;
- }
- if (view > 0) {
- image_ptr += (view * tex->get_z_size()) * image_size;
- }
- }
- glReadPixels(xo, yo, w, h, external_format,
- get_component_type(component_type), image_ptr);
- // We may have to reverse the byte ordering of the image if GL
- // didn't do it for us.
- if (color_mode && !_supports_bgr) {
- PTA_uchar new_image;
- const unsigned char *result =
- fix_component_ordering(new_image, image_ptr, image_size,
- external_format, tex);
- if (result != image_ptr) {
- memcpy(image_ptr, result, image_size);
- }
- }
- report_my_gl_errors();
- return true;
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::apply_fog
- // Access: Public, Virtual
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- apply_fog(Fog *fog) {
- Fog::Mode fmode = fog->get_mode();
- glFogf(GL_FOG_MODE, get_fog_mode_type(fmode));
- if (fmode == Fog::M_linear) {
- PN_stdfloat onset, opaque;
- fog->get_linear_range(onset, opaque);
- glFogf(GL_FOG_START, onset);
- glFogf(GL_FOG_END, opaque);
- } else {
- // Exponential fog is always camera-relative.
- glFogf(GL_FOG_DENSITY, fog->get_exp_density());
- }
- call_glFogfv(GL_FOG_COLOR, fog->get_color());
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_transform
- // Access: Protected
- // Description: Sends the indicated transform matrix to the graphics
- // API to be applied to future vertices.
- //
- // This transform is the internal_transform, already
- // converted into the GSG's internal coordinate system.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_transform() {
- #ifdef SUPPORT_FIXED_FUNCTION
- // OpenGL ES 2 does not support glLoadMatrix.
- const TransformState *transform = _internal_transform;
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glLoadMatrix(GL_MODELVIEW): " << transform->get_mat() << endl;
- }
- DO_PSTATS_STUFF(_transform_state_pcollector.add_level(1));
- glMatrixMode(GL_MODELVIEW);
- GLPf(LoadMatrix)(transform->get_mat().get_data());
- #endif
- _transform_stale = false;
- #ifndef OPENGLES_1
- if (_current_shader_context) {
- _current_shader_context->issue_parameters(Shader::SSD_transform);
- }
- #endif
- report_my_gl_errors();
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_shade_model
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_shade_model() {
- const ShadeModelAttrib *target_shade_model;
- _target_rs->get_attrib_def(target_shade_model);
- switch (target_shade_model->get_mode()) {
- case ShadeModelAttrib::M_smooth:
- glShadeModel(GL_SMOOTH);
- _flat_shade_model = false;
- break;
- case ShadeModelAttrib::M_flat:
- glShadeModel(GL_FLAT);
- _flat_shade_model = true;
- break;
- }
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifndef OPENGLES_1
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_shader
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_shader(bool state_has_changed) {
- ShaderContext *context = 0;
- Shader *shader = (Shader *)(_target_shader->get_shader());
- #ifndef SUPPORT_FIXED_FUNCTION
- // If we don't have a shader, apply the default shader.
- if (!shader) {
- shader = _default_shader;
- nassertv(shader != NULL);
- }
- #endif
- if (shader) {
- context = shader->prepare_now(get_prepared_objects(), this);
- }
- #ifndef SUPPORT_FIXED_FUNCTION
- // If it failed, try applying the default shader.
- if (shader != _default_shader && (context == 0 || !context->valid())) {
- shader = _default_shader;
- nassertv(shader != NULL);
- context = shader->prepare_now(get_prepared_objects(), this);
- }
- #endif
- if (context == 0 || (context->valid() == false)) {
- if (_current_shader_context != 0) {
- _current_shader_context->unbind();
- _current_shader = 0;
- _current_shader_context = 0;
- }
- } else {
- if (context != _current_shader_context) {
- // Use a completely different shader than before.
- // Unbind old shader, bind the new one.
- if (_current_shader_context != 0) {
- _current_shader_context->unbind();
- }
- context->bind();
- _current_shader = shader;
- _current_shader_context = context;
- context->issue_parameters(Shader::SSD_shaderinputs);
- } else {
- if (state_has_changed) {
- // Use the same shader as before, but with new input arguments.
- context->issue_parameters(Shader::SSD_shaderinputs);
- }
- }
- }
- report_my_gl_errors();
- }
- #endif // !OPENGLES_1
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_render_mode
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_render_mode() {
- const RenderModeAttrib *target_render_mode;
- _target_rs->get_attrib_def(target_render_mode);
- _render_mode = target_render_mode->get_mode();
- PN_stdfloat thickness = target_render_mode->get_thickness();
- _point_perspective = target_render_mode->get_perspective();
- #ifndef OPENGLES // glPolygonMode not supported by OpenGL ES.
- switch (_render_mode) {
- case RenderModeAttrib::M_unchanged:
- case RenderModeAttrib::M_filled:
- case RenderModeAttrib::M_filled_flat:
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- break;
- case RenderModeAttrib::M_wireframe:
- glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
- break;
- case RenderModeAttrib::M_point:
- glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
- break;
- default:
- GLCAT.error()
- << "Unknown render mode " << (int)_render_mode << endl;
- }
- #endif // OPENGLES
- // The thickness affects both the line width and the point size.
- if (thickness != _point_size) {
- glLineWidth(_point_size);
- #ifndef OPENGLES_2
- glPointSize(_point_size);
- #endif
- _point_size = thickness;
- }
- report_my_gl_errors();
- do_point_size();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_antialias
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_antialias() {
- const AntialiasAttrib *target_antialias;
- _target_rs->get_attrib_def(target_antialias);
- if (target_antialias->get_mode_type() == AntialiasAttrib::M_auto) {
- // In this special mode, we must enable antialiasing on a
- // case-by-case basis, because we enable it differently for
- // polygons and for points and lines.
- _auto_antialias_mode = true;
- } else {
- // Otherwise, explicitly enable or disable according to the bits
- // that are set. But if multisample is requested and supported,
- // don't use the other bits at all (they will be ignored by GL
- // anyway).
- _auto_antialias_mode = false;
- unsigned short mode = target_antialias->get_mode();
- if (_supports_multisample &&
- (mode & AntialiasAttrib::M_multisample) != 0) {
- enable_multisample_antialias(true);
- } else {
- enable_multisample_antialias(false);
- enable_line_smooth((mode & AntialiasAttrib::M_line) != 0);
- enable_point_smooth((mode & AntialiasAttrib::M_point) != 0);
- enable_polygon_smooth((mode & AntialiasAttrib::M_polygon) != 0);
- }
- }
- #ifndef OPENGLES_2
- switch (target_antialias->get_mode_quality()) {
- case AntialiasAttrib::M_faster:
- glHint(GL_LINE_SMOOTH_HINT, GL_FASTEST);
- glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST);
- #ifndef OPENGLES
- glHint(GL_POLYGON_SMOOTH_HINT, GL_FASTEST);
- #endif // OPENGLES
- break;
- case AntialiasAttrib::M_better:
- glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
- glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
- #ifndef OPENGLES
- glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
- #endif // OPENGLES
- break;
- default:
- glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
- glHint(GL_POINT_SMOOTH_HINT, GL_DONT_CARE);
- #ifndef OPENGLES
- glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
- #endif // OPENGLES
- break;
- }
- #endif // !OPENGLES_2
- report_my_gl_errors();
- }
- #ifdef SUPPORT_FIXED_FUNCTION // OpenGL ES 2.0 doesn't support rescaling normals.
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_rescale_normal
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_rescale_normal() {
- RescaleNormalAttrib::Mode mode = RescaleNormalAttrib::M_none;
- const RescaleNormalAttrib *target_rescale_normal;
- if (_target_rs->get_attrib(target_rescale_normal)) {
- mode = target_rescale_normal->get_mode();
- }
- switch (mode) {
- case RescaleNormalAttrib::M_none:
- glDisable(GL_NORMALIZE);
- if (_supports_rescale_normal && support_rescale_normal) {
- glDisable(GL_RESCALE_NORMAL);
- }
- break;
- case RescaleNormalAttrib::M_rescale:
- if (_supports_rescale_normal && support_rescale_normal) {
- glEnable(GL_RESCALE_NORMAL);
- glDisable(GL_NORMALIZE);
- } else {
- glEnable(GL_NORMALIZE);
- }
- break;
- case RescaleNormalAttrib::M_normalize:
- glEnable(GL_NORMALIZE);
- if (_supports_rescale_normal && support_rescale_normal) {
- glDisable(GL_RESCALE_NORMAL);
- }
- break;
- default:
- GLCAT.error()
- << "Unknown rescale_normal mode " << (int)mode << endl;
- }
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- // PandaCompareFunc - 1 + 0x200 === GL_NEVER, etc. order is sequential
- #define PANDA_TO_GL_COMPAREFUNC(PANDACMPFUNC) (PANDACMPFUNC-1 +0x200)
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_depth_test
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_depth_test() {
- const DepthTestAttrib *target_depth_test;
- _target_rs->get_attrib_def(target_depth_test);
- DepthTestAttrib::PandaCompareFunc mode = target_depth_test->get_mode();
- if (mode == DepthTestAttrib::M_none) {
- enable_depth_test(false);
- } else {
- enable_depth_test(true);
- glDepthFunc(PANDA_TO_GL_COMPAREFUNC(mode));
- }
- report_my_gl_errors();
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_alpha_test
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_alpha_test() {
- if (_target_shader->get_flag(ShaderAttrib::F_subsume_alpha_test)) {
- enable_alpha_test(false);
- } else {
- const AlphaTestAttrib *target_alpha_test;
- _target_rs->get_attrib_def(target_alpha_test);
- AlphaTestAttrib::PandaCompareFunc mode = target_alpha_test->get_mode();
- if (mode == AlphaTestAttrib::M_none) {
- enable_alpha_test(false);
- } else {
- nassertv(GL_NEVER == (AlphaTestAttrib::M_never-1+0x200));
- glAlphaFunc(PANDA_TO_GL_COMPAREFUNC(mode), target_alpha_test->get_reference_alpha());
- enable_alpha_test(true);
- }
- }
- }
- #endif // SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_depth_write
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_depth_write() {
- const DepthWriteAttrib *target_depth_write;
- _target_rs->get_attrib_def(target_depth_write);
- DepthWriteAttrib::Mode mode = target_depth_write->get_mode();
- if (mode == DepthWriteAttrib::M_off) {
- #ifdef GSG_VERBOSE
- GLCAT.spam()
- << "glDepthMask(GL_FALSE)" << endl;
- #endif
- glDepthMask(GL_FALSE);
- } else {
- #ifdef GSG_VERBOSE
- GLCAT.spam()
- << "glDepthMask(GL_TRUE)" << endl;
- #endif
- glDepthMask(GL_TRUE);
- }
- report_my_gl_errors();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_cull_face
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_cull_face() {
- const CullFaceAttrib *target_cull_face;
- _target_rs->get_attrib_def(target_cull_face);
- CullFaceAttrib::Mode mode = target_cull_face->get_effective_mode();
- switch (mode) {
- case CullFaceAttrib::M_cull_none:
- glDisable(GL_CULL_FACE);
- break;
- case CullFaceAttrib::M_cull_clockwise:
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
- break;
- case CullFaceAttrib::M_cull_counter_clockwise:
- glEnable(GL_CULL_FACE);
- glCullFace(GL_FRONT);
- break;
- default:
- GLCAT.error()
- << "invalid cull face mode " << (int)mode << endl;
- break;
- }
- report_my_gl_errors();
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_fog
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_fog() {
- const FogAttrib *target_fog;
- _target_rs->get_attrib_def(target_fog);
- if (!target_fog->is_off()) {
- enable_fog(true);
- Fog *fog = target_fog->get_fog();
- nassertv(fog != (Fog *)NULL);
- apply_fog(fog);
- } else {
- enable_fog(false);
- }
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_depth_offset
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_depth_offset() {
- const DepthOffsetAttrib *target_depth_offset = (const DepthOffsetAttrib *)
- _target_rs->get_attrib_def(DepthOffsetAttrib::get_class_slot());
- int offset = target_depth_offset->get_offset();
- if (offset != 0) {
- // The relationship between these two parameters is a little
- // unclear and poorly explained in the GL man pages.
- glPolygonOffset((GLfloat) -offset, (GLfloat) -offset);
- enable_polygon_offset(true);
- } else {
- enable_polygon_offset(false);
- }
- PN_stdfloat min_value = target_depth_offset->get_min_value();
- PN_stdfloat max_value = target_depth_offset->get_max_value();
- #ifdef GSG_VERBOSE
- GLCAT.spam()
- << "glDepthRange(" << min_value << ", " << max_value << ")" << endl;
- #endif
- #ifdef OPENGLES
- // OpenGL ES uses a single-precision call.
- glDepthRangef((GLclampf)min_value, (GLclampf)max_value);
- #else
- // Mainline OpenGL uses a double-precision call.
- glDepthRange((GLclampd)min_value, (GLclampd)max_value);
- #endif // OPENGLES
- report_my_gl_errors();
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_material
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_material() {
- static Material empty;
- const Material *material;
- const MaterialAttrib *target_material;
- _target_rs->get_attrib_def(target_material);
- if (target_material == (MaterialAttrib *)NULL ||
- target_material->is_off()) {
- material = ∅
- } else {
- material = target_material->get_material();
- }
- bool has_material_force_color = _has_material_force_color;
- #ifndef NDEBUG
- if (_show_texture_usage) {
- // In show_texture_usage mode, all colors are white, so as not
- // to contaminate the texture color. This means we disable
- // lighting materials too.
- material = ∅
- has_material_force_color = false;
- }
- #endif // NDEBUG
- #ifdef OPENGLES
- const GLenum face = GL_FRONT_AND_BACK;
- #else
- GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT;
- #endif
- call_glMaterialfv(face, GL_SPECULAR, material->get_specular());
- call_glMaterialfv(face, GL_EMISSION, material->get_emission());
- glMaterialf(face, GL_SHININESS, min(material->get_shininess(), (PN_stdfloat)128.0));
- if (material->has_ambient() && material->has_diffuse()) {
- // The material has both an ambient and diffuse specified. This
- // means we do not need glMaterialColor().
- glDisable(GL_COLOR_MATERIAL);
- call_glMaterialfv(face, GL_AMBIENT, material->get_ambient());
- call_glMaterialfv(face, GL_DIFFUSE, material->get_diffuse());
- } else if (material->has_ambient()) {
- // The material specifies an ambient, but not a diffuse component.
- // The diffuse component comes from the object's color.
- call_glMaterialfv(face, GL_AMBIENT, material->get_ambient());
- if (has_material_force_color) {
- glDisable(GL_COLOR_MATERIAL);
- call_glMaterialfv(face, GL_DIFFUSE, _material_force_color);
- } else {
- #ifndef OPENGLES
- glColorMaterial(face, GL_DIFFUSE);
- #endif // OPENGLES
- glEnable(GL_COLOR_MATERIAL);
- }
- } else if (material->has_diffuse()) {
- // The material specifies a diffuse, but not an ambient component.
- // The ambient component comes from the object's color.
- call_glMaterialfv(face, GL_DIFFUSE, material->get_diffuse());
- if (has_material_force_color) {
- glDisable(GL_COLOR_MATERIAL);
- call_glMaterialfv(face, GL_AMBIENT, _material_force_color);
- } else {
- #ifndef OPENGLES
- glColorMaterial(face, GL_AMBIENT);
- #endif // OPENGLES
- glEnable(GL_COLOR_MATERIAL);
- }
- } else {
- // The material specifies neither a diffuse nor an ambient
- // component. Both components come from the object's color.
- if (has_material_force_color) {
- glDisable(GL_COLOR_MATERIAL);
- call_glMaterialfv(face, GL_AMBIENT, _material_force_color);
- call_glMaterialfv(face, GL_DIFFUSE, _material_force_color);
- } else {
- #ifndef OPENGLES
- glColorMaterial(face, GL_AMBIENT_AND_DIFFUSE);
- #endif // OPENGLES
- glEnable(GL_COLOR_MATERIAL);
- }
- }
- #ifndef OPENGLES
- glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, material->get_local());
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, material->get_twoside());
- if (gl_separate_specular_color) {
- glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SEPARATE_SPECULAR_COLOR);
- } else {
- glLightModeli(GL_LIGHT_MODEL_COLOR_CONTROL, GL_SINGLE_COLOR);
- }
- #endif
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_blending
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_blending() {
- // Handle the color_write attrib. If color_write is off, then
- // all the other blending-related stuff doesn't matter. If the
- // device doesn't support color-write, we use blending tricks
- // to effectively disable color write.
- const ColorWriteAttrib *target_color_write;
- _target_rs->get_attrib_def(target_color_write);
- unsigned int color_channels =
- target_color_write->get_channels() & _color_write_mask;
- if (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write)) {
- color_channels &= ~(ColorWriteAttrib::C_alpha);
- }
- if (color_channels == ColorWriteAttrib::C_off) {
- int color_write_slot = ColorWriteAttrib::get_class_slot();
- enable_multisample_alpha_one(false);
- enable_multisample_alpha_mask(false);
- if (gl_color_mask) {
- enable_blend(false);
- set_color_write_mask(ColorWriteAttrib::C_off);
- } else {
- enable_blend(true);
- _glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_ZERO, GL_ONE);
- }
- return;
- } else {
- set_color_write_mask(color_channels);
- }
- const ColorBlendAttrib *target_color_blend;
- _target_rs->get_attrib_def(target_color_blend);
- CPT(ColorBlendAttrib) color_blend = target_color_blend;
- ColorBlendAttrib::Mode color_blend_mode = target_color_blend->get_mode();
- const TransparencyAttrib *target_transparency;
- _target_rs->get_attrib_def(target_transparency);
- TransparencyAttrib::Mode transparency_mode = target_transparency->get_mode();
- _color_blend_involves_color_scale = color_blend->involves_color_scale();
- // Is there a color blend set?
- if (color_blend_mode != ColorBlendAttrib::M_none) {
- enable_multisample_alpha_one(false);
- enable_multisample_alpha_mask(false);
- enable_blend(true);
- _glBlendEquation(get_blend_equation_type(color_blend_mode));
- glBlendFunc(get_blend_func(color_blend->get_operand_a()),
- get_blend_func(color_blend->get_operand_b()));
- if (_color_blend_involves_color_scale) {
- // Apply the current color scale to the blend mode.
- _glBlendColor(_current_color_scale[0], _current_color_scale[1],
- _current_color_scale[2], _current_color_scale[3]);
- } else {
- LColor c = color_blend->get_color();
- _glBlendColor(c[0], c[1], c[2], c[3]);
- }
- return;
- }
- // No color blend; is there a transparency set?
- switch (transparency_mode) {
- case TransparencyAttrib::M_none:
- case TransparencyAttrib::M_binary:
- break;
- case TransparencyAttrib::M_alpha:
- case TransparencyAttrib::M_dual:
- enable_multisample_alpha_one(false);
- enable_multisample_alpha_mask(false);
- enable_blend(true);
- _glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- return;
- case TransparencyAttrib::M_multisample:
- // We need to enable *both* of these in M_multisample case.
- enable_multisample_alpha_one(true);
- enable_multisample_alpha_mask(true);
- enable_blend(false);
- return;
- case TransparencyAttrib::M_multisample_mask:
- enable_multisample_alpha_one(false);
- enable_multisample_alpha_mask(true);
- enable_blend(false);
- return;
- default:
- GLCAT.error()
- << "invalid transparency mode " << (int)transparency_mode << endl;
- break;
- }
- if (_line_smooth_enabled || _point_smooth_enabled) {
- // If we have either of these turned on, we also need to have
- // blend mode enabled in order to see it.
- enable_multisample_alpha_one(false);
- enable_multisample_alpha_mask(false);
- enable_blend(true);
- _glBlendEquation(GL_FUNC_ADD);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- return;
- }
- // For best polygon smoothing, we need:
- // (1) a frame buffer that supports alpha
- // (2) sort polygons front-to-back
- // (3) glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
- //
- // Since these modes have other implications for the application, we
- // don't attempt to do this by default. If you really want good
- // polygon smoothing (and you don't have multisample support), do
- // all this yourself.
- // Nothing's set, so disable blending.
- enable_multisample_alpha_one(false);
- enable_multisample_alpha_mask(false);
- enable_blend(false);
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::bind_light
- // Access: Public, Virtual
- // Description: Called the first time a particular light has been
- // bound to a given id within a frame, this should set
- // up the associated hardware light with the light's
- // properties.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- bind_light(PointLight *light_obj, const NodePath &light, int light_id) {
- // static PStatCollector _draw_set_state_light_bind_point_pcollector("Draw:Set State:Light:Bind:Point");
- // PStatGPUTimer timer(this, _draw_set_state_light_bind_point_pcollector);
- GLenum id = get_light_id(light_id);
- static const LColor black(0.0f, 0.0f, 0.0f, 1.0f);
- call_glLightfv(id, GL_AMBIENT, black);
- call_glLightfv(id, GL_DIFFUSE, get_light_color(light_obj));
- call_glLightfv(id, GL_SPECULAR, light_obj->get_specular_color());
- // Position needs to specify x, y, z, and w
- // w == 1 implies non-infinite position
- CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
- LPoint3 pos = light_obj->get_point() * transform->get_mat();
- LPoint4 fpos(pos[0], pos[1], pos[2], 1.0f);
- call_glLightfv(id, GL_POSITION, fpos);
- // GL_SPOT_DIRECTION is not significant when cutoff == 180
- // Exponent == 0 implies uniform light distribution
- glLightf(id, GL_SPOT_EXPONENT, 0.0f);
- // Cutoff == 180 means uniform point light source
- glLightf(id, GL_SPOT_CUTOFF, 180.0f);
- const LVecBase3 &att = light_obj->get_attenuation();
- glLightf(id, GL_CONSTANT_ATTENUATION, att[0]);
- glLightf(id, GL_LINEAR_ATTENUATION, att[1]);
- glLightf(id, GL_QUADRATIC_ATTENUATION, att[2]);
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::bind_light
- // Access: Public, Virtual
- // Description: Called the first time a particular light has been
- // bound to a given id within a frame, this should set
- // up the associated hardware light with the light's
- // properties.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- bind_light(DirectionalLight *light_obj, const NodePath &light, int light_id) {
- // static PStatCollector _draw_set_state_light_bind_directional_pcollector("Draw:Set State:Light:Bind:Directional");
- // PStatGPUTimer timer(this, _draw_set_state_light_bind_directional_pcollector);
- pair<DirectionalLights::iterator, bool> lookup = _dlights.insert(DirectionalLights::value_type(light, DirectionalLightFrameData()));
- DirectionalLightFrameData &fdata = (*lookup.first).second;
- if (lookup.second) {
- // The light was not computed yet this frame. Compute it now.
- CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
- LVector3 dir = light_obj->get_direction() * transform->get_mat();
- fdata._neg_dir.set(-dir[0], -dir[1], -dir[2], 0);
- }
- GLenum id = get_light_id( light_id );
- static const LColor black(0.0f, 0.0f, 0.0f, 1.0f);
- call_glLightfv(id, GL_AMBIENT, black);
- call_glLightfv(id, GL_DIFFUSE, get_light_color(light_obj));
- call_glLightfv(id, GL_SPECULAR, light_obj->get_specular_color());
- // Position needs to specify x, y, z, and w.
- // w == 0 implies light is at infinity
- call_glLightfv(id, GL_POSITION, fdata._neg_dir);
- // GL_SPOT_DIRECTION is not significant when cutoff == 180
- // In this case, position x, y, z specifies direction
- // Exponent == 0 implies uniform light distribution
- glLightf(id, GL_SPOT_EXPONENT, 0.0f);
- // Cutoff == 180 means uniform point light source
- glLightf(id, GL_SPOT_CUTOFF, 180.0f);
- // Default attenuation values (only spotlight and point light can
- // modify these)
- glLightf(id, GL_CONSTANT_ATTENUATION, 1.0f);
- glLightf(id, GL_LINEAR_ATTENUATION, 0.0f);
- glLightf(id, GL_QUADRATIC_ATTENUATION, 0.0f);
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::bind_light
- // Access: Public, Virtual
- // Description: Called the first time a particular light has been
- // bound to a given id within a frame, this should set
- // up the associated hardware light with the light's
- // properties.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- bind_light(Spotlight *light_obj, const NodePath &light, int light_id) {
- // static PStatCollector _draw_set_state_light_bind_spotlight_pcollector("Draw:Set State:Light:Bind:Spotlight");
- // PStatGPUTimer timer(this, _draw_set_state_light_bind_spotlight_pcollector);
- Lens *lens = light_obj->get_lens();
- nassertv(lens != (Lens *)NULL);
- GLenum id = get_light_id(light_id);
- static const LColor black(0.0f, 0.0f, 0.0f, 1.0f);
- call_glLightfv(id, GL_AMBIENT, black);
- call_glLightfv(id, GL_DIFFUSE, get_light_color(light_obj));
- call_glLightfv(id, GL_SPECULAR, light_obj->get_specular_color());
- // Position needs to specify x, y, z, and w
- // w == 1 implies non-infinite position
- CPT(TransformState) transform = light.get_transform(_scene_setup->get_scene_root().get_parent());
- const LMatrix4 &light_mat = transform->get_mat();
- LPoint3 pos = lens->get_nodal_point() * light_mat;
- LVector3 dir = lens->get_view_vector() * light_mat;
- LPoint4 fpos(pos[0], pos[1], pos[2], 1.0f);
- call_glLightfv(id, GL_POSITION, fpos);
- call_glLightfv(id, GL_SPOT_DIRECTION, dir);
- glLightf(id, GL_SPOT_EXPONENT, light_obj->get_exponent());
- glLightf(id, GL_SPOT_CUTOFF, lens->get_hfov() * 0.5f);
- const LVecBase3 &att = light_obj->get_attenuation();
- glLightf(id, GL_CONSTANT_ATTENUATION, att[0]);
- glLightf(id, GL_LINEAR_ATTENUATION, att[1]);
- glLightf(id, GL_QUADRATIC_ATTENUATION, att[2]);
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_IMMEDIATE_MODE
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::draw_immediate_simple_primitives
- // Access: Protected
- // Description: Uses the ImmediateModeSender to draw a series of
- // primitives of the indicated type.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- draw_immediate_simple_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode) {
- int num_vertices = reader->get_num_vertices();
- _vertices_immediate_pcollector.add_level(num_vertices);
- glBegin(mode);
- if (reader->is_indexed()) {
- for (int v = 0; v < num_vertices; ++v) {
- _sender.set_vertex(reader->get_vertex(v));
- _sender.issue_vertex();
- }
- } else {
- _sender.set_vertex(reader->get_first_vertex());
- for (int v = 0; v < num_vertices; ++v) {
- _sender.issue_vertex();
- }
- }
- glEnd();
- }
- #endif // SUPPORT_IMMEDIATE_MODE
- #ifdef SUPPORT_IMMEDIATE_MODE
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::draw_immediate_composite_primitives
- // Access: Protected
- // Description: Uses the ImmediateModeSender to draw a series of
- // primitives of the indicated type. This form is for
- // primitive types like tristrips which must involve
- // several begin/end groups.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- draw_immediate_composite_primitives(const GeomPrimitivePipelineReader *reader, GLenum mode) {
- int num_vertices = reader->get_num_vertices();
- _vertices_immediate_pcollector.add_level(num_vertices);
- CPTA_int ends = reader->get_ends();
- int num_unused_vertices_per_primitive = reader->get_object()->get_num_unused_vertices_per_primitive();
- if (reader->is_indexed()) {
- int begin = 0;
- CPTA_int::const_iterator ei;
- for (ei = ends.begin(); ei != ends.end(); ++ei) {
- int end = (*ei);
- glBegin(mode);
- for (int v = begin; v < end; ++v) {
- _sender.set_vertex(reader->get_vertex(v));
- _sender.issue_vertex();
- }
- glEnd();
- begin = end + num_unused_vertices_per_primitive;
- }
- } else {
- _sender.set_vertex(reader->get_first_vertex());
- int begin = 0;
- CPTA_int::const_iterator ei;
- for (ei = ends.begin(); ei != ends.end(); ++ei) {
- int end = (*ei);
- glBegin(mode);
- for (int v = begin; v < end; ++v) {
- _sender.issue_vertex();
- }
- glEnd();
- begin = end + num_unused_vertices_per_primitive;
- }
- }
- }
- #endif // SUPPORT_IMMEDIATE_MODE
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::gl_flush
- // Access: Protected, Virtual
- // Description: Calls glFlush().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- gl_flush() const {
- PStatTimer timer(_flush_pcollector);
- glFlush();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::gl_get_error
- // Access: Protected, Virtual
- // Description: Returns the result of glGetError().
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- gl_get_error() const {
- if (_check_errors) {
- PStatTimer timer(_check_error_pcollector);
- return glGetError();
- } else {
- return GL_NO_ERROR;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::report_errors_loop
- // Access: Protected, Static
- // Description: The internal implementation of report_errors().
- // Don't call this function; use report_errors()
- // instead. The return value is true if everything is
- // ok, or false if we should shut down.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- report_errors_loop(int line, const char *source_file, GLenum error_code,
- int &error_count) {
- while ((gl_max_errors < 0 || error_count < gl_max_errors) &&
- (error_code != GL_NO_ERROR)) {
- GLCAT.error()
- << "at " << line << " of " << source_file << " : "
- << get_error_string(error_code) << "\n";
- error_code = glGetError();
- error_count++;
- }
- return (error_code == GL_NO_ERROR);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_error_string
- // Access: Protected, Static
- // Description: Returns an error string for an OpenGL error code.
- ////////////////////////////////////////////////////////////////////
- string CLP(GraphicsStateGuardian)::
- get_error_string(GLenum error_code) {
- // We used to use gluErrorString here, but I (rdb) took it out
- // because that was really the only function we used from GLU.
- // The idea with the error table was taken from SGI's sample implementation.
- static const char *error_strings[GL_OUT_OF_MEMORY - GL_INVALID_ENUM + 1] = {
- "invalid enumerant",
- "invalid value",
- "invalid operation",
- "stack overflow",
- "stack underflow",
- "out of memory",
- };
- if (error_code == GL_NO_ERROR) {
- return "no error";
- #ifndef OPENGLES
- } else if (error_code == GL_TABLE_TOO_LARGE) {
- return "table too large";
- #endif
- } else if (error_code >= GL_INVALID_ENUM && error_code <= GL_OUT_OF_MEMORY) {
- return error_strings[error_code - GL_INVALID_ENUM];
- }
- // Other error, somehow? Just display the error code then.
- ostringstream strm;
- strm << "GL error " << (int)error_code;
- return strm.str();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::show_gl_string
- // Access: Protected
- // Description: Outputs the result of glGetString() on the indicated
- // tag. The output string is returned.
- ////////////////////////////////////////////////////////////////////
- string CLP(GraphicsStateGuardian)::
- show_gl_string(const string &name, GLenum id) {
- string result;
- const GLubyte *text = glGetString(id);
- if (text == (const GLubyte *)NULL) {
- GLCAT.warning()
- << "Unable to query " << name << "\n";
- } else {
- result = (const char *)text;
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << name << " = " << result << "\n";
- }
- }
- return result;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::query_gl_version
- // Access: Protected, Virtual
- // Description: Queries the runtime version of OpenGL in use.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- query_gl_version() {
- _gl_vendor = show_gl_string("GL_VENDOR", GL_VENDOR);
- _gl_renderer = show_gl_string("GL_RENDERER", GL_RENDERER);
- _gl_version = show_gl_string("GL_VERSION", GL_VERSION);
- _gl_version_major = 0;
- _gl_version_minor = 0;
- // This is the most preposterous driver bug: NVIDIA drivers will claim
- // that the version is 1.2 as long as the process is named pview.exe!
- #ifndef OPENGLES
- if (_gl_version.substr(0, 10) == "1.2 NVIDIA") {
- Filename exec_name = ExecutionEnvironment::get_binary_name();
- if (cmp_nocase(exec_name.get_basename(), "pview.exe") == 0) {
- glGetIntegerv(GL_MAJOR_VERSION, &_gl_version_major);
- glGetIntegerv(GL_MINOR_VERSION, &_gl_version_minor);
- if (glGetError() == GL_INVALID_ENUM) {
- _gl_version_major = 1;
- _gl_version_minor = 2;
- GLCAT.warning()
- << "Driver possibly misreported GL_VERSION! Unable to detect "
- "correct OpenGL version.\n";
- } else if (_gl_version_major != 1 || _gl_version_minor != 2) {
- GLCAT.debug()
- << "Driver misreported GL_VERSION! Correct version detected as "
- << _gl_version_major << "." << _gl_version_minor << "\n";
- }
- return;
- }
- }
- // If we asked for a GL 3 context, let's first try and see if we
- // can use the OpenGL 3 way to query version.
- if (gl_version.get_num_words() > 0 && gl_version[0] >= 3) {
- glGetIntegerv(GL_MAJOR_VERSION, &_gl_version_major);
- glGetIntegerv(GL_MINOR_VERSION, &_gl_version_minor);
- if (_gl_version_major >= 1) {
- // Fair enough, seems to check out.
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "Detected OpenGL version: "
- << _gl_version_major << "." << _gl_version_minor << "\n";
- }
- return;
- }
- }
- #endif // !OPENGLES
- // Otherwise, parse the GL_VERSION string.
- if (_gl_version.empty()) {
- GLCAT.error() << "Unable to detect OpenGL version\n";
- } else {
- string input = _gl_version;
- // Skip any initial words that don't begin with a digit.
- while (!input.empty() && !isdigit(input[0])) {
- size_t space = input.find(' ');
- if (space == string::npos) {
- break;
- }
- size_t next = space + 1;
- while (next < input.length() && isspace(input[next])) {
- ++next;
- }
- input = input.substr(next);
- }
- // Truncate after the first space.
- size_t space = input.find(' ');
- if (space != string::npos) {
- input = input.substr(0, space);
- }
- vector_string components;
- tokenize(input, components, ".");
- if (components.size() >= 1) {
- string_to_int(components[0], _gl_version_major);
- }
- if (components.size() >= 2) {
- string_to_int(components[1], _gl_version_minor);
- }
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "GL_VERSION decoded to: "
- << _gl_version_major << "." << _gl_version_minor
- << "\n";
- }
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::query_glsl_version
- // Access: Protected
- // Description: Queries the supported GLSL version.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- query_glsl_version() {
- _gl_shadlang_ver_major = 0;
- _gl_shadlang_ver_minor = 0;
- #ifndef OPENGLES
- // OpenGL 2.0 introduces GLSL in the core. In 1.x, it is an extension.
- if (_gl_version_major >= 2 || has_extension("GL_ARB_shading_language_100")) {
- string ver = show_gl_string("GL_SHADING_LANGUAGE_VERSION", GL_SHADING_LANGUAGE_VERSION);
- _gl_shadlang_ver_major = 1;
- _gl_shadlang_ver_minor = (_gl_version_major >= 2) ? 1 : 0;
- if (ver.empty() ||
- sscanf(ver.c_str(), "%d.%d", &_gl_shadlang_ver_major,
- &_gl_shadlang_ver_minor) != 2) {
- GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n";
- }
- }
- #elif !defined(OPENGLES_1)
- // OpenGL ES 2.0 and above has shader support built-in.
- string ver = show_gl_string("GL_SHADING_LANGUAGE_VERSION", GL_SHADING_LANGUAGE_VERSION);
- _gl_shadlang_ver_major = 1;
- _gl_shadlang_ver_minor = 0;
- if (ver.empty() ||
- sscanf(ver.c_str(), "OpenGL ES GLSL %d.%d", &_gl_shadlang_ver_major,
- &_gl_shadlang_ver_minor) != 2) {
- GLCAT.warning() << "Invalid GL_SHADING_LANGUAGE_VERSION format.\n";
- }
- #endif
- #ifndef OPENGLES_1
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "Detected GLSL version: "
- << _gl_shadlang_ver_major << "." << _gl_shadlang_ver_minor << "\n";
- }
- #endif
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::save_extensions
- // Access: Protected
- // Description: Separates the string returned by GL_EXTENSIONS (or
- // glx or wgl extensions) into its individual tokens
- // and saves them in the _extensions member.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- save_extensions(const char *extensions) {
- if (extensions != (const char *)NULL) {
- vector_string tokens;
- extract_words(extensions, tokens);
- vector_string::iterator ti;
- for (ti = tokens.begin(); ti != tokens.end(); ++ti) {
- _extensions.insert(*ti);
- }
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_extra_extensions
- // Access: Protected, Virtual
- // Description: This may be redefined by a derived class (e.g. glx or
- // wgl) to get whatever further extensions strings may
- // be appropriate to that interface, in addition to the
- // GL extension strings return by glGetString().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- get_extra_extensions() {
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::report_extensions
- // Access: Protected
- // Description: Outputs the list of GL extensions to notify, if debug
- // mode is enabled.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- report_extensions() const {
- if (GLCAT.is_debug()) {
- ostream &out = GLCAT.debug();
- out << "GL Extensions:\n";
- size_t maxlen = 0;
- pset<string>::const_iterator ei;
- for (ei = _extensions.begin(); ei != _extensions.end(); ++ei) {
- size_t len = (*ei).size();
- out << " " << (*ei);
- // Display a second column.
- if (len <= 38) {
- if (++ei != _extensions.end()) {
- for (int i = len; i < 38; ++i) {
- out.put(' ');
- }
- out << ' ' << (*ei);
- } else {
- out.put('\n');
- break;
- }
- }
- out.put('\n');
- }
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_extension_func
- // Access: Public
- // Description: Returns the pointer to the GL extension function with
- // the indicated name, or NULL if the function is not
- // available.
- ////////////////////////////////////////////////////////////////////
- void *CLP(GraphicsStateGuardian)::
- get_extension_func(const char *name) {
- // First, look in the static-compiled namespace. If we were
- // compiled to expect at least a certain minimum runtime version of
- // OpenGL, then we can expect those extension functions to be
- // available at compile time. Somewhat more reliable than poking
- // around in the runtime pointers.
- static struct {
- const char *name;
- void *fptr;
- } compiled_function_table[] = {
- #ifdef EXPECT_GL_VERSION_1_2
- { "glBlendColor", (void *)&glBlendColor },
- { "glBlendEquation", (void *)&glBlendEquation },
- { "glDrawRangeElements", (void *)&glDrawRangeElements },
- { "glTexImage3D", (void *)&glTexImage3D },
- { "glTexSubImage3D", (void *)&glTexSubImage3D },
- { "glCopyTexSubImage3D", (void *)&glCopyTexSubImage3D },
- #endif
- #ifdef EXPECT_GL_VERSION_1_3
- { "glActiveTexture", (void *)&glActiveTexture },
- { "glClientActiveTexture", (void *)&glClientActiveTexture },
- { "glCompressedTexImage1D", (void *)&glCompressedTexImage1D },
- { "glCompressedTexImage2D", (void *)&glCompressedTexImage2D },
- { "glCompressedTexImage3D", (void *)&glCompressedTexImage3D },
- { "glCompressedTexSubImage1D", (void *)&glCompressedTexSubImage1D },
- { "glCompressedTexSubImage2D", (void *)&glCompressedTexSubImage2D },
- { "glCompressedTexSubImage3D", (void *)&glCompressedTexSubImage3D },
- { "glGetCompressedTexImage", (void *)&glGetCompressedTexImage },
- { "glMultiTexCoord1f", (void *)&glMultiTexCoord1f },
- { "glMultiTexCoord2", (void *)&glMultiTexCoord2 },
- { "glMultiTexCoord3", (void *)&glMultiTexCoord3 },
- { "glMultiTexCoord4", (void *)&glMultiTexCoord4 },
- #endif
- #ifdef EXPECT_GL_VERSION_1_4
- { "glPointParameterfv", (void *)&glPointParameterfv },
- { "glSecondaryColorPointer", (void *)&glSecondaryColorPointer },
- #endif
- #ifdef EXPECT_GL_VERSION_1_5
- { "glBeginQuery", (void *)&glBeginQuery },
- { "glBindBuffer", (void *)&glBindBuffer },
- { "glBufferData", (void *)&glBufferData },
- { "glBufferSubData", (void *)&glBufferSubData },
- { "glDeleteBuffers", (void *)&glDeleteBuffers },
- { "glDeleteQueries", (void *)&glDeleteQueries },
- { "glEndQuery", (void *)&glEndQuery },
- { "glGenBuffers", (void *)&glGenBuffers },
- { "glGenQueries", (void *)&glGenQueries },
- { "glGetQueryObjectuiv", (void *)&glGetQueryObjectuiv },
- { "glGetQueryiv", (void *)&glGetQueryiv },
- #endif
- #ifdef OPENGLES
- { "glActiveTexture", (void *)&glActiveTexture },
- #ifndef OPENGLES_2
- { "glClientActiveTexture", (void *)&glClientActiveTexture },
- #endif
- { "glBindBuffer", (void *)&glBindBuffer },
- { "glBufferData", (void *)&glBufferData },
- { "glBufferSubData", (void *)&glBufferSubData },
- { "glDeleteBuffers", (void *)&glDeleteBuffers },
- { "glGenBuffers", (void *)&glGenBuffers },
- #endif
- { NULL, NULL }
- };
- int i = 0;
- while (compiled_function_table[i].name != NULL) {
- if (strcmp(compiled_function_table[i].name, name) == 0) {
- return compiled_function_table[i].fptr;
- }
- ++i;
- }
- // If the extension function wasn't compiled in, then go get it from
- // the runtime. There's a different interface for each API.
- return do_get_extension_func(name);
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_get_extension_func
- // Access: Public, Virtual
- // Description: This is the virtual implementation of
- // get_extension_func(). Each API-specific GL
- // implementation will map this method to the
- // appropriate API call to retrieve the extension
- // function pointer. Returns NULL if the function is
- // not available.
- ////////////////////////////////////////////////////////////////////
- void *CLP(GraphicsStateGuardian)::
- do_get_extension_func(const char *) {
- return NULL;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::set_draw_buffer
- // Access: Protected
- // Description: Sets up the glDrawBuffer to render into the buffer
- // indicated by the RenderBuffer object. This only sets
- // up the color and aux bits; it does not affect the depth,
- // stencil, accum layers.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- set_draw_buffer(int rbtype) {
- #ifndef OPENGLES // Draw buffers not supported by OpenGL ES.
- if (_current_fbo) {
- GLuint buffers[16];
- int nbuffers = 0;
- int index = 0;
- if (_current_properties->get_color_bits() > 0) {
- if (rbtype & RenderBuffer::T_left) {
- buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
- }
- ++index;
- if (_current_properties->is_stereo()) {
- if (rbtype & RenderBuffer::T_right) {
- buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
- }
- ++index;
- }
- }
- for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
- if (rbtype & (RenderBuffer::T_aux_rgba_0 << i)) {
- buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
- }
- ++index;
- }
- for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
- if (rbtype & (RenderBuffer::T_aux_hrgba_0 << i)) {
- buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
- }
- ++index;
- }
- for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
- if (rbtype & (RenderBuffer::T_aux_float_0 << i)) {
- buffers[nbuffers++] = GL_COLOR_ATTACHMENT0_EXT + index;
- }
- ++index;
- }
- _glDrawBuffers(nbuffers, buffers);
- } else {
- switch (rbtype & RenderBuffer::T_color) {
- case RenderBuffer::T_front:
- glDrawBuffer(GL_FRONT);
- break;
- case RenderBuffer::T_back:
- glDrawBuffer(GL_BACK);
- break;
- case RenderBuffer::T_right:
- glDrawBuffer(GL_RIGHT);
- break;
- case RenderBuffer::T_left:
- glDrawBuffer(GL_LEFT);
- break;
- case RenderBuffer::T_front_right:
- nassertv(_current_properties->is_stereo());
- glDrawBuffer(GL_FRONT_RIGHT);
- break;
- case RenderBuffer::T_front_left:
- nassertv(_current_properties->is_stereo());
- glDrawBuffer(GL_FRONT_LEFT);
- break;
- case RenderBuffer::T_back_right:
- nassertv(_current_properties->is_stereo());
- glDrawBuffer(GL_BACK_RIGHT);
- break;
- case RenderBuffer::T_back_left:
- nassertv(_current_properties->is_stereo());
- glDrawBuffer(GL_BACK_LEFT);
- break;
- default:
- break;
- }
- }
- #endif // OPENGLES
- // Also ensure that any global color channels are masked out.
- set_color_write_mask(_color_write_mask);
- report_my_gl_errors();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::set_read_buffer
- // Access: Protected
- // Description: Sets up the glReadBuffer to render into the buffer
- // indicated by the RenderBuffer object. This only sets
- // up the color bits; it does not affect the depth,
- // stencil, accum layers.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- set_read_buffer(int rbtype) {
- #ifndef OPENGLES // Draw buffers not supported by OpenGL ES.
- if (rbtype & (RenderBuffer::T_depth | RenderBuffer::T_stencil)) {
- // Special case: don't have to call ReadBuffer for these.
- return;
- }
- if (_current_fbo) {
- GLuint buffer = GL_COLOR_ATTACHMENT0_EXT;
- int index = 1;
- if (_current_properties->is_stereo()) {
- if (rbtype & RenderBuffer::T_right) {
- buffer = GL_COLOR_ATTACHMENT1_EXT;
- }
- ++index;
- }
- for (int i = 0; i < _current_properties->get_aux_rgba(); ++i) {
- if (rbtype & (RenderBuffer::T_aux_rgba_0 << i)) {
- buffer = GL_COLOR_ATTACHMENT0_EXT + index;
- }
- ++index;
- }
- for (int i = 0; i < _current_properties->get_aux_hrgba(); ++i) {
- if (rbtype & (RenderBuffer::T_aux_hrgba_0 << i)) {
- buffer = GL_COLOR_ATTACHMENT0_EXT + index;
- }
- ++index;
- }
- for (int i = 0; i < _current_properties->get_aux_float(); ++i) {
- if (rbtype & (RenderBuffer::T_aux_float_0 << i)) {
- buffer = GL_COLOR_ATTACHMENT0_EXT + index;
- }
- ++index;
- }
- glReadBuffer(buffer);
- } else {
- switch (rbtype & RenderBuffer::T_color) {
- case RenderBuffer::T_front:
- glReadBuffer(GL_FRONT);
- break;
- case RenderBuffer::T_back:
- glReadBuffer(GL_BACK);
- break;
- case RenderBuffer::T_right:
- glReadBuffer(GL_RIGHT);
- break;
- case RenderBuffer::T_left:
- glReadBuffer(GL_LEFT);
- break;
- case RenderBuffer::T_front_right:
- glReadBuffer(GL_FRONT_RIGHT);
- break;
- case RenderBuffer::T_front_left:
- glReadBuffer(GL_FRONT_LEFT);
- break;
- case RenderBuffer::T_back_right:
- glReadBuffer(GL_BACK_RIGHT);
- break;
- case RenderBuffer::T_back_left:
- glReadBuffer(GL_BACK_LEFT);
- break;
- default:
- break;
- }
- }
- report_my_gl_errors();
- #endif // OPENGLES
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_numeric_type
- // Access: Protected, Static
- // Description: Maps from the Geom's internal numeric type symbols
- // to GL's.
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- get_numeric_type(Geom::NumericType numeric_type) {
- switch (numeric_type) {
- case Geom::NT_uint16:
- return GL_UNSIGNED_SHORT;
- case Geom::NT_uint32:
- #ifndef OPENGLES_1
- return GL_UNSIGNED_INT;
- #else
- break;
- #endif
- case Geom::NT_uint8:
- case Geom::NT_packed_dcba:
- case Geom::NT_packed_dabc:
- return GL_UNSIGNED_BYTE;
- case Geom::NT_float32:
- return GL_FLOAT;
- case Geom::NT_float64:
- #ifndef OPENGLES
- return GL_DOUBLE;
- #else
- break;
- #endif
- case Geom::NT_stdfloat:
- // Shouldn't happen, display error.
- break;
- case Geom::NT_int8:
- return GL_BYTE;
- case Geom::NT_int16:
- return GL_SHORT;
- case Geom::NT_int32:
- #ifndef OPENGLES_1
- return GL_INT;
- #else
- break;
- #endif
- case Geom::NT_packed_ufloat:
- #ifndef OPENGLES
- return GL_UNSIGNED_INT_10F_11F_11F_REV;
- #else
- break;
- #endif
- }
- GLCAT.error()
- << "Invalid NumericType value (" << (int)numeric_type << ")\n";
- return GL_UNSIGNED_BYTE;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_texture_target
- // Access: Protected
- // Description: Maps from the Texture's texture type symbols to
- // GL's.
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- get_texture_target(Texture::TextureType texture_type) const {
- switch (texture_type) {
- case Texture::TT_1d_texture:
- // There are no 1D textures in OpenGL ES. Fall back to 2D textures.
- #ifndef OPENGLES
- return GL_TEXTURE_1D;
- #endif
- case Texture::TT_2d_texture:
- return GL_TEXTURE_2D;
- case Texture::TT_3d_texture:
- #ifndef OPENGLES_1
- if (_supports_3d_texture) {
- return GL_TEXTURE_3D;
- }
- #endif
- return GL_NONE;
- case Texture::TT_2d_texture_array:
- #ifndef OPENGLES
- if (_supports_2d_texture_array) {
- return GL_TEXTURE_2D_ARRAY_EXT;
- }
- #endif
- return GL_NONE;
- case Texture::TT_cube_map:
- if (_supports_cube_map) {
- return GL_TEXTURE_CUBE_MAP;
- } else {
- return GL_NONE;
- }
- case Texture::TT_buffer_texture:
- #ifndef OPENGLES
- if (_supports_buffer_texture) {
- return GL_TEXTURE_BUFFER;
- }
- #endif
- return GL_NONE;
- }
- GLCAT.error() << "Invalid Texture::TextureType value!\n";
- return GL_TEXTURE_2D;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_texture_wrap_mode
- // Access: Protected
- // Description: Maps from the Texture's internal wrap mode symbols to
- // GL's.
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- get_texture_wrap_mode(SamplerState::WrapMode wm) const {
- if (gl_ignore_clamp) {
- return GL_REPEAT;
- }
- switch (wm) {
- case SamplerState::WM_clamp:
- return _edge_clamp;
- case SamplerState::WM_repeat:
- return GL_REPEAT;
- case SamplerState::WM_mirror:
- return _mirror_repeat;
- case SamplerState::WM_mirror_once:
- return _mirror_border_clamp;
- case SamplerState::WM_border_color:
- return _border_clamp;
- case SamplerState::WM_invalid:
- break;
- }
- GLCAT.error() << "Invalid SamplerState::WrapMode value!\n";
- return _edge_clamp;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_panda_wrap_mode
- // Access: Protected, Static
- // Description: Maps from the GL's internal wrap mode symbols to
- // Panda's.
- ////////////////////////////////////////////////////////////////////
- SamplerState::WrapMode CLP(GraphicsStateGuardian)::
- get_panda_wrap_mode(GLenum wm) {
- switch (wm) {
- #ifndef OPENGLES
- case GL_CLAMP:
- #endif
- case GL_CLAMP_TO_EDGE:
- return SamplerState::WM_clamp;
- #ifndef OPENGLES
- case GL_CLAMP_TO_BORDER:
- return SamplerState::WM_border_color;
- #endif
- case GL_REPEAT:
- return SamplerState::WM_repeat;
- #ifndef OPENGLES
- case GL_MIRROR_CLAMP_EXT:
- case GL_MIRROR_CLAMP_TO_EDGE_EXT:
- return SamplerState::WM_mirror;
- case GL_MIRROR_CLAMP_TO_BORDER_EXT:
- return SamplerState::WM_mirror_once;
- #endif
- }
- GLCAT.error() << "Unexpected GL wrap mode " << (int)wm << "\n";
- return SamplerState::WM_clamp;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_texture_filter_type
- // Access: Protected, Static
- // Description: Maps from the Texture's internal filter type symbols
- // to GL's.
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- get_texture_filter_type(SamplerState::FilterType ft, bool ignore_mipmaps) {
- if (gl_ignore_filters) {
- return GL_NEAREST;
- } else if (ignore_mipmaps) {
- switch (ft) {
- case SamplerState::FT_nearest_mipmap_nearest:
- case SamplerState::FT_nearest:
- return GL_NEAREST;
- case SamplerState::FT_linear:
- case SamplerState::FT_linear_mipmap_nearest:
- case SamplerState::FT_nearest_mipmap_linear:
- case SamplerState::FT_linear_mipmap_linear:
- return GL_LINEAR;
- case SamplerState::FT_shadow:
- return GL_LINEAR;
- case SamplerState::FT_default:
- case SamplerState::FT_invalid:
- break;
- }
- } else {
- switch (ft) {
- case SamplerState::FT_nearest:
- return GL_NEAREST;
- case SamplerState::FT_linear:
- return GL_LINEAR;
- case SamplerState::FT_nearest_mipmap_nearest:
- return GL_NEAREST_MIPMAP_NEAREST;
- case SamplerState::FT_linear_mipmap_nearest:
- return GL_LINEAR_MIPMAP_NEAREST;
- case SamplerState::FT_nearest_mipmap_linear:
- return GL_NEAREST_MIPMAP_LINEAR;
- case SamplerState::FT_linear_mipmap_linear:
- return GL_LINEAR_MIPMAP_LINEAR;
- case SamplerState::FT_shadow:
- return GL_LINEAR;
- case SamplerState::FT_default:
- case SamplerState::FT_invalid:
- break;
- }
- }
- GLCAT.error() << "Invalid SamplerState::FilterType value!\n";
- return GL_NEAREST;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_panda_filter_type
- // Access: Protected, Static
- // Description: Maps from the GL's internal filter type symbols
- // to Panda's.
- ////////////////////////////////////////////////////////////////////
- SamplerState::FilterType CLP(GraphicsStateGuardian)::
- get_panda_filter_type(GLenum ft) {
- switch (ft) {
- case GL_NEAREST:
- return SamplerState::FT_nearest;
- case GL_LINEAR:
- return SamplerState::FT_linear;
- case GL_NEAREST_MIPMAP_NEAREST:
- return SamplerState::FT_nearest_mipmap_nearest;
- case GL_LINEAR_MIPMAP_NEAREST:
- return SamplerState::FT_linear_mipmap_nearest;
- case GL_NEAREST_MIPMAP_LINEAR:
- return SamplerState::FT_nearest_mipmap_linear;
- case GL_LINEAR_MIPMAP_LINEAR:
- return SamplerState::FT_linear_mipmap_linear;
- }
- GLCAT.error() << "Unexpected GL filter type " << (int)ft << "\n";
- return SamplerState::FT_linear;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_component_type
- // Access: Protected, Static
- // Description: Maps from the Texture's internal ComponentType symbols
- // to GL's.
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- get_component_type(Texture::ComponentType component_type) {
- switch (component_type) {
- case Texture::T_unsigned_byte:
- return GL_UNSIGNED_BYTE;
- case Texture::T_unsigned_short:
- return GL_UNSIGNED_SHORT;
- case Texture::T_float:
- return GL_FLOAT;
- case Texture::T_unsigned_int_24_8:
- if (_supports_depth_stencil) {
- return GL_UNSIGNED_INT_24_8_EXT;
- } else {
- return GL_UNSIGNED_BYTE;
- }
- case Texture::T_int:
- #ifndef OPENGLES_1
- return GL_INT;
- #endif
- default:
- GLCAT.error() << "Invalid Texture::Type value!\n";
- return GL_UNSIGNED_BYTE;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_external_image_format
- // Access: Protected
- // Description: Maps from the Texture's Format symbols
- // to GL's.
- ////////////////////////////////////////////////////////////////////
- GLint CLP(GraphicsStateGuardian)::
- get_external_image_format(Texture *tex) const {
- Texture::CompressionMode compression = tex->get_ram_image_compression();
- Texture::Format format = tex->get_format();
- if (compression != Texture::CM_off &&
- get_supports_compressed_texture_format(compression)) {
- switch (compression) {
- case Texture::CM_on:
- #ifndef OPENGLES
- switch (format) {
- case Texture::F_color_index:
- case Texture::F_depth_component:
- case Texture::F_depth_component16:
- case Texture::F_depth_component24:
- case Texture::F_depth_component32:
- case Texture::F_depth_stencil:
- // This shouldn't be possible.
- nassertr(false, GL_RGB);
- break;
- case Texture::F_rgba:
- case Texture::F_rgbm:
- case Texture::F_rgba4:
- case Texture::F_rgba8:
- case Texture::F_rgba12:
- case Texture::F_rgba16:
- case Texture::F_rgba32:
- case Texture::F_rgba8i:
- return GL_COMPRESSED_RGBA;
- case Texture::F_rgb:
- case Texture::F_rgb5:
- case Texture::F_rgba5:
- case Texture::F_rgb8:
- case Texture::F_rgb8i:
- case Texture::F_rgb12:
- case Texture::F_rgb332:
- case Texture::F_rgb16:
- case Texture::F_rgb32:
- return GL_COMPRESSED_RGB;
- case Texture::F_alpha:
- return GL_COMPRESSED_ALPHA;
- case Texture::F_red:
- case Texture::F_green:
- case Texture::F_blue:
- case Texture::F_r8i:
- case Texture::F_r16:
- case Texture::F_r32:
- case Texture::F_r32i:
- return GL_COMPRESSED_RED;
- case Texture::F_rg8i:
- case Texture::F_rg16:
- case Texture::F_rg32:
- return GL_COMPRESSED_RG;
- case Texture::F_luminance:
- return GL_COMPRESSED_LUMINANCE;
- case Texture::F_luminance_alpha:
- case Texture::F_luminance_alphamask:
- return GL_COMPRESSED_LUMINANCE_ALPHA;
- case Texture::F_srgb:
- return GL_COMPRESSED_SRGB;
- case Texture::F_srgb_alpha:
- return GL_COMPRESSED_SRGB_ALPHA;
- case Texture::F_sluminance:
- return GL_COMPRESSED_SLUMINANCE;
- case Texture::F_sluminance_alpha:
- return GL_COMPRESSED_SLUMINANCE_ALPHA;
- }
- #endif
- break;
- case Texture::CM_dxt1:
- #ifndef OPENGLES
- if (format == Texture::F_srgb_alpha) {
- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
- } else if (format == Texture::F_srgb) {
- return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
- } else
- #endif
- if (Texture::has_alpha(format)) {
- return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- } else {
- return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
- }
- case Texture::CM_dxt3:
- #ifndef OPENGLES
- if (format == Texture::F_srgb || format == Texture::F_srgb_alpha) {
- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
- }
- #endif
- #ifndef OPENGLES_1
- return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- #endif
- break;
- case Texture::CM_dxt5:
- #ifndef OPENGLES
- if (format == Texture::F_srgb || format == Texture::F_srgb_alpha) {
- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
- }
- #endif
- #ifndef OPENGLES_1
- return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- #endif
- break;
- case Texture::CM_fxt1:
- #ifndef OPENGLES
- if (Texture::has_alpha(format)) {
- return GL_COMPRESSED_RGBA_FXT1_3DFX;
- } else {
- return GL_COMPRESSED_RGB_FXT1_3DFX;
- }
- #endif
- break;
- #ifdef OPENGLES
- case Texture::CM_pvr1_2bpp:
- if (Texture::has_alpha(format)) {
- return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
- } else {
- return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
- }
- case Texture::CM_pvr1_4bpp:
- if (Texture::has_alpha(format)) {
- return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
- } else {
- return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
- }
- #else
- case Texture::CM_pvr1_2bpp:
- case Texture::CM_pvr1_4bpp:
- break;
- #endif // OPENGLES
- case Texture::CM_default:
- case Texture::CM_off:
- case Texture::CM_dxt2:
- case Texture::CM_dxt4:
- // This shouldn't happen.
- nassertr(false, GL_RGB);
- break;
- }
- }
- switch (format) {
- #ifndef OPENGLES
- case Texture::F_color_index:
- return GL_COLOR_INDEX;
- #endif
- case Texture::F_depth_component:
- case Texture::F_depth_component16:
- case Texture::F_depth_component24:
- case Texture::F_depth_component32:
- return GL_DEPTH_COMPONENT;
- case Texture::F_depth_stencil:
- return _supports_depth_stencil ? GL_DEPTH_STENCIL : GL_DEPTH_COMPONENT;
- #ifndef OPENGLES
- case Texture::F_red:
- case Texture::F_r16:
- case Texture::F_r32:
- return GL_RED;
- case Texture::F_green:
- return GL_GREEN;
- case Texture::F_blue:
- return GL_BLUE;
- #endif
- case Texture::F_alpha:
- #ifdef SUPPORT_FIXED_FUNCTION
- return GL_ALPHA;
- #else
- return GL_RED;
- #endif
- #ifndef OPENGLES_1
- case Texture::F_rg16:
- case Texture::F_rg32:
- return GL_RG;
- #endif
- case Texture::F_rgb:
- case Texture::F_rgb5:
- case Texture::F_rgb8:
- case Texture::F_rgb12:
- case Texture::F_rgb332:
- case Texture::F_rgb16:
- case Texture::F_rgb32:
- case Texture::F_srgb:
- #ifdef OPENGLES
- return GL_RGB;
- #else
- return _supports_bgr ? GL_BGR : GL_RGB;
- #endif
- case Texture::F_rgba:
- case Texture::F_rgbm:
- case Texture::F_rgba4:
- case Texture::F_rgba5:
- case Texture::F_rgba8:
- case Texture::F_rgba12:
- case Texture::F_rgba16:
- case Texture::F_rgba32:
- case Texture::F_srgb_alpha:
- #ifdef OPENGLES_2
- return GL_RGBA;
- #else
- return _supports_bgr ? GL_BGRA : GL_RGBA;
- #endif
- case Texture::F_luminance:
- case Texture::F_sluminance:
- #ifdef SUPPORT_FIXED_FUNCTION
- return GL_LUMINANCE;
- #else
- return GL_RED;
- #endif
- case Texture::F_luminance_alphamask:
- case Texture::F_luminance_alpha:
- case Texture::F_sluminance_alpha:
- #ifdef SUPPORT_FIXED_FUNCTION
- return GL_LUMINANCE_ALPHA;
- #else
- return GL_RG;
- #endif
- #ifndef OPENGLES
- case Texture::F_r8i:
- case Texture::F_r32i:
- return GL_RED_INTEGER;
- case Texture::F_rg8i:
- return GL_RG_INTEGER;
- case Texture::F_rgb8i:
- return GL_RGB_INTEGER;
- case Texture::F_rgba8i:
- return GL_RGBA_INTEGER;
- #endif
- default:
- break;
- }
- GLCAT.error()
- << "Invalid Texture::Format value in get_external_image_format(): "
- << tex->get_format() << "\n";
- return GL_RGB;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_internal_image_format
- // Access: Protected
- // Description: Maps from the Texture's Format symbols to a
- // suitable internal format for GL textures.
- ////////////////////////////////////////////////////////////////////
- GLint CLP(GraphicsStateGuardian)::
- get_internal_image_format(Texture *tex, bool force_sized) const {
- Texture::CompressionMode compression = tex->get_compression();
- if (compression == Texture::CM_default) {
- compression = (compressed_textures) ? Texture::CM_on : Texture::CM_off;
- }
- Texture::Format format = tex->get_format();
- if (tex->get_render_to_texture()) {
- // no compression for render targets
- compression = Texture::CM_off;
- }
- bool is_3d = (tex->get_texture_type() == Texture::TT_3d_texture ||
- tex->get_texture_type() == Texture::TT_2d_texture_array);
- if (get_supports_compressed_texture_format(compression)) {
- switch (compression) {
- case Texture::CM_on:
- // The user asked for just generic compression. OpenGL supports
- // requesting just generic compression, but we'd like to go ahead
- // and request a specific type (if we can figure out an
- // appropriate choice), since that makes saving the result as a
- // pre-compressed texture more dependable--this way, we will know
- // which compression algorithm was applied.
- switch (format) {
- case Texture::F_color_index:
- case Texture::F_depth_component:
- case Texture::F_depth_component16:
- case Texture::F_depth_component24:
- case Texture::F_depth_component32:
- case Texture::F_depth_stencil:
- case Texture::F_r8i:
- case Texture::F_rg8i:
- case Texture::F_rgb8i:
- case Texture::F_rgba8i:
- case Texture::F_r32i:
- // Unsupported; fall through to below.
- break;
- case Texture::F_rgbm:
- if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
- return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- }
- #ifndef OPENGLES
- if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
- return GL_COMPRESSED_RGBA_FXT1_3DFX;
- }
- return GL_COMPRESSED_RGBA;
- #endif
- break;
- case Texture::F_rgba4:
- #ifndef OPENGLES_1
- if (get_supports_compressed_texture_format(Texture::CM_dxt3) && !is_3d) {
- return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- }
- #endif
- #ifndef OPENGLES
- if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
- return GL_COMPRESSED_RGBA_FXT1_3DFX;
- }
- return GL_COMPRESSED_RGBA;
- #endif
- break;
- case Texture::F_rgba:
- case Texture::F_rgba8:
- case Texture::F_rgba12:
- case Texture::F_rgba16:
- case Texture::F_rgba32:
- #ifndef OPENGLES_1
- if (get_supports_compressed_texture_format(Texture::CM_dxt5) && !is_3d) {
- return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- }
- #endif
- #ifndef OPENGLES
- if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
- return GL_COMPRESSED_RGBA_FXT1_3DFX;
- }
- return GL_COMPRESSED_RGBA;
- #endif
- break;
- case Texture::F_rgb:
- case Texture::F_rgb5:
- case Texture::F_rgba5:
- case Texture::F_rgb8:
- case Texture::F_rgb12:
- case Texture::F_rgb332:
- case Texture::F_rgb16:
- case Texture::F_rgb32:
- if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
- return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
- }
- #ifndef OPENGLES
- if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
- return GL_COMPRESSED_RGB_FXT1_3DFX;
- }
- return GL_COMPRESSED_RGB;
- #endif
- break;
- case Texture::F_alpha:
- #ifndef OPENGLES_1
- if (get_supports_compressed_texture_format(Texture::CM_dxt5) && !is_3d) {
- return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- }
- #endif
- #ifndef OPENGLES
- if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
- return GL_COMPRESSED_RGBA_FXT1_3DFX;
- }
- return GL_COMPRESSED_ALPHA;
- #endif
- break;
- case Texture::F_red:
- case Texture::F_green:
- case Texture::F_blue:
- case Texture::F_r16:
- case Texture::F_r32:
- if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
- return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
- }
- #ifndef OPENGLES
- if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
- return GL_COMPRESSED_RGB_FXT1_3DFX;
- }
- return GL_COMPRESSED_RED;
- #endif
- break;
- case Texture::F_rg16:
- case Texture::F_rg32:
- if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
- return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
- }
- #ifndef OPENGLES
- if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
- return GL_COMPRESSED_RGB_FXT1_3DFX;
- }
- return GL_COMPRESSED_RG;
- #endif
- break;
- case Texture::F_luminance:
- if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
- return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
- }
- #ifndef OPENGLES
- if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
- return GL_COMPRESSED_RGB_FXT1_3DFX;
- }
- return GL_COMPRESSED_LUMINANCE;
- #endif
- break;
- case Texture::F_luminance_alpha:
- case Texture::F_luminance_alphamask:
- #ifndef OPENGLES_1
- if (get_supports_compressed_texture_format(Texture::CM_dxt5) && !is_3d) {
- return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- }
- #endif
- #ifndef OPENGLES
- if (get_supports_compressed_texture_format(Texture::CM_fxt1) && !is_3d) {
- return GL_COMPRESSED_RGBA_FXT1_3DFX;
- }
- return GL_COMPRESSED_LUMINANCE_ALPHA;
- #endif
- break;
- #ifndef OPENGLES
- case Texture::F_srgb:
- if (get_supports_compressed_texture_format(Texture::CM_dxt1) && !is_3d) {
- return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
- }
- return GL_COMPRESSED_SRGB;
- case Texture::F_srgb_alpha:
- if (get_supports_compressed_texture_format(Texture::CM_dxt5) && !is_3d) {
- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
- }
- return GL_COMPRESSED_SRGB_ALPHA;
- case Texture::F_sluminance:
- return GL_COMPRESSED_SLUMINANCE;
- case Texture::F_sluminance_alpha:
- return GL_COMPRESSED_SLUMINANCE_ALPHA;
- #else
- // For now, we don't support compressed sRGB textures in OpenGL ES.
- case Texture::F_srgb:
- case Texture::F_srgb_alpha:
- case Texture::F_sluminance:
- case Texture::F_sluminance_alpha:
- break;
- #endif
- }
- break;
- case Texture::CM_dxt1:
- #ifndef OPENGLES
- if (format == Texture::F_srgb_alpha) {
- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;
- } else if (format == Texture::F_srgb) {
- return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
- } else
- #endif
- if (Texture::has_alpha(format)) {
- return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
- } else {
- return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
- }
- case Texture::CM_dxt3:
- #ifndef OPENGLES
- if (format == Texture::F_srgb || format == Texture::F_srgb_alpha) {
- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
- }
- #endif
- #ifndef OPENGLES_1
- return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
- #endif
- break;
- case Texture::CM_dxt5:
- #ifndef OPENGLES
- if (format == Texture::F_srgb || format == Texture::F_srgb_alpha) {
- return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
- }
- #endif
- #ifndef OPENGLES_1
- return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
- #endif
- case Texture::CM_fxt1:
- #ifndef OPENGLES
- if (Texture::has_alpha(format)) {
- return GL_COMPRESSED_RGBA_FXT1_3DFX;
- } else {
- return GL_COMPRESSED_RGB_FXT1_3DFX;
- }
- #endif
- break;
- #ifdef OPENGLES
- case Texture::CM_pvr1_2bpp:
- if (Texture::has_alpha(format)) {
- return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
- } else {
- return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
- }
- case Texture::CM_pvr1_4bpp:
- if (Texture::has_alpha(format)) {
- return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
- } else {
- return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
- }
- #else
- case Texture::CM_pvr1_2bpp:
- case Texture::CM_pvr1_4bpp:
- break;
- #endif
- case Texture::CM_default:
- case Texture::CM_off:
- case Texture::CM_dxt2:
- case Texture::CM_dxt4:
- // No compression: fall through to below.
- break;
- }
- }
- switch (format) {
- #ifndef OPENGLES
- case Texture::F_color_index:
- return GL_COLOR_INDEX;
- #endif
- case Texture::F_depth_stencil:
- if (_supports_depth_stencil) {
- #ifndef OPENGLES
- if (tex->get_component_type() == Texture::T_float) {
- return GL_DEPTH32F_STENCIL8;
- } else
- #endif
- {
- return force_sized ? GL_DEPTH24_STENCIL8 : GL_DEPTH_STENCIL;
- }
- }
- // Fall through.
- case Texture::F_depth_component:
- #ifndef OPENGLES
- if (tex->get_component_type() == Texture::T_float) {
- return GL_DEPTH_COMPONENT32F;
- } else
- #endif
- {
- return force_sized ? GL_DEPTH_COMPONENT16 : GL_DEPTH_COMPONENT;
- }
- case Texture::F_depth_component16:
- #ifdef OPENGLES
- return GL_DEPTH_COMPONENT16_OES;
- #else
- return GL_DEPTH_COMPONENT16;
- #endif
- case Texture::F_depth_component24:
- #ifdef OPENGLES
- if (_supports_depth24) {
- return GL_DEPTH_COMPONENT24_OES;
- } else {
- return GL_DEPTH_COMPONENT16_OES;
- }
- #else
- return GL_DEPTH_COMPONENT24;
- #endif
- case Texture::F_depth_component32:
- #ifdef OPENGLES
- if (_supports_depth32) {
- return GL_DEPTH_COMPONENT32_OES;
- } else if (_supports_depth24) {
- return GL_DEPTH_COMPONENT24_OES;
- } else {
- return GL_DEPTH_COMPONENT16_OES;
- }
- #else
- if (tex->get_component_type() == Texture::T_float) {
- return GL_DEPTH_COMPONENT32F;
- } else {
- return GL_DEPTH_COMPONENT32;
- }
- #endif
- case Texture::F_rgba:
- case Texture::F_rgbm:
- #ifndef OPENGLES_1
- if (tex->get_component_type() == Texture::T_float) {
- return GL_RGBA16F;
- } else
- #endif
- #ifndef OPENGLES
- if (tex->get_component_type() == Texture::T_unsigned_short) {
- return GL_RGBA16;
- } else
- #endif
- {
- return force_sized ? GL_RGBA8 : GL_RGBA;
- }
- case Texture::F_rgba4:
- return GL_RGBA4;
- #ifdef OPENGLES
- case Texture::F_rgba8:
- return GL_RGBA8_OES;
- case Texture::F_rgba12:
- return force_sized ? GL_RGBA8 : GL_RGBA;
- #else
- case Texture::F_rgba8:
- return GL_RGBA8;
- case Texture::F_r8i:
- if (tex->get_component_type() == Texture::T_unsigned_byte) {
- return GL_R8UI;
- } else {
- return GL_R8I;
- }
- case Texture::F_rg8i:
- if (tex->get_component_type() == Texture::T_unsigned_byte) {
- return GL_RG8UI;
- } else {
- return GL_RG8I;
- }
- case Texture::F_rgb8i:
- if (tex->get_component_type() == Texture::T_unsigned_byte) {
- return GL_RGB8UI;
- } else {
- return GL_RGB8I;
- }
- case Texture::F_rgba8i:
- if (tex->get_component_type() == Texture::T_unsigned_byte) {
- return GL_RGBA8UI;
- } else {
- return GL_RGBA8I;
- }
- case Texture::F_rgba12:
- return GL_RGBA12;
- #endif // OPENGLES
- #ifndef OPENGLES
- case Texture::F_rgba16:
- if (tex->get_component_type() == Texture::T_float) {
- return GL_RGBA16F;
- } else {
- return GL_RGBA16;
- }
- case Texture::F_rgba32:
- return GL_RGBA32F;
- #endif // OPENGLES
- case Texture::F_rgb:
- if (tex->get_component_type() == Texture::T_float) {
- return GL_RGB16F;
- } else {
- return force_sized ? GL_RGB8 : GL_RGB;
- }
- case Texture::F_rgb5:
- #ifdef OPENGLES
- // Close enough.
- return GL_RGB565_OES;
- #else
- return GL_RGB5;
- #endif
- case Texture::F_rgba5:
- return GL_RGB5_A1;
- #ifdef OPENGLES
- case Texture::F_rgb8:
- return GL_RGB8_OES;
- case Texture::F_rgb12:
- return force_sized ? GL_RGB8 : GL_RGB;
- case Texture::F_rgb16:
- return GL_RGB16F;
- #else
- case Texture::F_rgb8:
- return GL_RGB8;
- case Texture::F_rgb12:
- return GL_RGB12;
- case Texture::F_rgb16:
- if (tex->get_component_type() == Texture::T_float) {
- return GL_RGB16F;
- } else {
- return GL_RGB16;
- }
- #endif // OPENGLES
- case Texture::F_rgb32:
- return GL_RGB32F;
- #ifndef OPENGLES
- case Texture::F_rgb332:
- return GL_R3_G3_B2;
- #endif
- #if defined(OPENGLES_2)
- case Texture::F_r16:
- return GL_R16F_EXT;
- case Texture::F_rg16:
- return GL_RG16F_EXT;
- #elif !defined(OPENGLES_1)
- case Texture::F_r16:
- if (tex->get_component_type() == Texture::T_float) {
- return GL_R16F;
- } else {
- return GL_R16;
- }
- case Texture::F_rg16:
- if (tex->get_component_type() == Texture::T_float) {
- return GL_RG16F;
- } else {
- return GL_RG16;
- }
- #endif
- #ifndef OPENGLES_1
- case Texture::F_r32:
- return GL_R32F;
- case Texture::F_rg32:
- return GL_RG32F;
- case Texture::F_red:
- case Texture::F_green:
- case Texture::F_blue:
- return force_sized ? GL_R8 : GL_RED;
- #endif
- case Texture::F_alpha:
- #ifdef SUPPORT_FIXED_FUNCTION
- return force_sized ? GL_ALPHA8 : GL_ALPHA;
- #else
- return force_sized ? GL_R8 : GL_RED;
- #endif
- case Texture::F_luminance:
- #ifndef OPENGLES
- if (tex->get_component_type() == Texture::T_float) {
- return GL_LUMINANCE16F_ARB;
- } else if (tex->get_component_type() == Texture::T_unsigned_short) {
- return GL_LUMINANCE16;
- } else
- #endif // OPENGLES
- {
- return force_sized ? GL_LUMINANCE8 : GL_LUMINANCE;
- }
- case Texture::F_luminance_alpha:
- case Texture::F_luminance_alphamask:
- #ifndef OPENGLES
- if (tex->get_component_type() == Texture::T_float || tex->get_component_type() == Texture::T_unsigned_short) {
- return GL_LUMINANCE_ALPHA16F_ARB;
- } else
- #endif // OPENGLES
- {
- return force_sized ? GL_LUMINANCE8_ALPHA8 : GL_LUMINANCE_ALPHA;
- }
- #ifndef OPENGLES_1
- case Texture::F_srgb:
- #ifndef OPENGLES
- return GL_SRGB8;
- #endif
- case Texture::F_srgb_alpha:
- return GL_SRGB8_ALPHA8;
- #endif
- #ifndef OPENGLES
- case Texture::F_sluminance:
- return GL_SLUMINANCE8;
- case Texture::F_sluminance_alpha:
- return GL_SLUMINANCE8_ALPHA8;
- #endif
- #ifndef OPENGLES
- case Texture::F_r32i:
- return GL_R32I;
- #endif
- default:
- GLCAT.error()
- << "Invalid image format in get_internal_image_format(): "
- << (int)tex->get_format() << "\n";
- return force_sized ? GL_RGB8 : GL_RGB;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::is_mipmap_filter
- // Access: Protected, Static
- // Description: Returns true if the indicated GL minfilter type
- // represents a mipmap format, false otherwise.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- is_mipmap_filter(GLenum min_filter) {
- switch (min_filter) {
- case GL_NEAREST_MIPMAP_NEAREST:
- case GL_LINEAR_MIPMAP_NEAREST:
- case GL_NEAREST_MIPMAP_LINEAR:
- case GL_LINEAR_MIPMAP_LINEAR:
- return true;
- default:
- return false;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::is_compressed_format
- // Access: Protected, Static
- // Description: Returns true if the indicated GL internal format
- // represents a compressed texture format, false
- // otherwise.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- is_compressed_format(GLenum format) {
- switch (format) {
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- #ifdef OPENGLES
- case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
- case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
- case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
- case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
- #else
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- case GL_COMPRESSED_RGB_FXT1_3DFX:
- case GL_COMPRESSED_RGBA_FXT1_3DFX:
- case GL_COMPRESSED_RGB:
- case GL_COMPRESSED_RGBA:
- case GL_COMPRESSED_ALPHA:
- case GL_COMPRESSED_LUMINANCE:
- case GL_COMPRESSED_LUMINANCE_ALPHA:
- #endif
- return true;
- default:
- return false;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_texture_apply_mode_type
- // Access: Protected, Static
- // Description: Maps from the texture stage's mode types
- // to the corresponding OpenGL ids
- ////////////////////////////////////////////////////////////////////
- GLint CLP(GraphicsStateGuardian)::
- get_texture_apply_mode_type(TextureStage::Mode am) {
- #ifdef SUPPORT_FIXED_FUNCTION
- switch (am) {
- case TextureStage::M_modulate: return GL_MODULATE;
- case TextureStage::M_decal: return GL_DECAL;
- case TextureStage::M_blend: return GL_BLEND;
- case TextureStage::M_replace: return GL_REPLACE;
- case TextureStage::M_add: return GL_ADD;
- case TextureStage::M_combine: return GL_COMBINE;
- case TextureStage::M_blend_color_scale: return GL_BLEND;
- case TextureStage::M_modulate_glow: return GL_MODULATE;
- case TextureStage::M_modulate_gloss: return GL_MODULATE;
- default:
- // Other modes shouldn't get here. Fall through and error.
- break;
- }
- GLCAT.error()
- << "Invalid TextureStage::Mode value" << endl;
- return GL_MODULATE;
- #else
- return 0;
- #endif
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_texture_combine_type
- // Access: Protected, Static
- // Description: Maps from the texture stage's CombineMode types
- // to the corresponding OpenGL ids
- ////////////////////////////////////////////////////////////////////
- GLint CLP(GraphicsStateGuardian)::
- get_texture_combine_type(TextureStage::CombineMode cm) {
- #ifdef SUPPORT_FIXED_FUNCTION
- switch (cm) {
- case TextureStage::CM_undefined: // fall through
- case TextureStage::CM_replace: return GL_REPLACE;
- case TextureStage::CM_modulate: return GL_MODULATE;
- case TextureStage::CM_add: return GL_ADD;
- case TextureStage::CM_add_signed: return GL_ADD_SIGNED;
- case TextureStage::CM_interpolate: return GL_INTERPOLATE;
- case TextureStage::CM_subtract: return GL_SUBTRACT;
- case TextureStage::CM_dot3_rgb: return GL_DOT3_RGB;
- case TextureStage::CM_dot3_rgba: return GL_DOT3_RGBA;
- }
- GLCAT.error()
- << "Invalid TextureStage::CombineMode value" << endl;
- #endif
- return GL_REPLACE;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_texture_src_type
- // Access: Protected
- // Description: Maps from the texture stage's CombineSource types
- // to the corresponding OpenGL ids
- ////////////////////////////////////////////////////////////////////
- GLint CLP(GraphicsStateGuardian)::
- get_texture_src_type(TextureStage::CombineSource cs,
- int last_stage, int last_saved_result,
- int this_stage) const {
- #ifdef SUPPORT_FIXED_FUNCTION
- switch (cs) {
- case TextureStage::CS_undefined: // fall through
- case TextureStage::CS_texture: return GL_TEXTURE;
- case TextureStage::CS_constant: return GL_CONSTANT;
- case TextureStage::CS_primary_color: return GL_PRIMARY_COLOR;
- case TextureStage::CS_constant_color_scale: return GL_CONSTANT;
- case TextureStage::CS_previous:
- if (last_stage == this_stage - 1) {
- return GL_PREVIOUS;
- } else if (last_stage == -1) {
- return GL_PRIMARY_COLOR;
- } else if (_supports_texture_saved_result) {
- return GL_TEXTURE0 + last_stage;
- } else {
- GLCAT.warning()
- << "Current OpenGL driver does not support texture crossbar blending.\n";
- return GL_PRIMARY_COLOR;
- }
- case TextureStage::CS_last_saved_result:
- if (last_saved_result == this_stage - 1) {
- return GL_PREVIOUS;
- } else if (last_saved_result == -1) {
- return GL_PRIMARY_COLOR;
- } else if (_supports_texture_saved_result) {
- return GL_TEXTURE0 + last_saved_result;
- } else {
- GLCAT.warning()
- << "Current OpenGL driver does not support texture crossbar blending.\n";
- return GL_PRIMARY_COLOR;
- }
- }
- GLCAT.error()
- << "Invalid TextureStage::CombineSource value" << endl;
- #endif
- return GL_TEXTURE;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_texture_operand_type
- // Access: Protected, Static
- // Description: Maps from the texture stage's CombineOperand types
- // to the corresponding OpenGL ids
- ////////////////////////////////////////////////////////////////////
- GLint CLP(GraphicsStateGuardian)::
- get_texture_operand_type(TextureStage::CombineOperand co) {
- switch (co) {
- case TextureStage::CO_undefined: // fall through
- case TextureStage::CO_src_alpha: return GL_SRC_ALPHA;
- case TextureStage::CO_one_minus_src_alpha: return GL_ONE_MINUS_SRC_ALPHA;
- case TextureStage::CO_src_color: return GL_SRC_COLOR;
- case TextureStage::CO_one_minus_src_color: return GL_ONE_MINUS_SRC_COLOR;
- }
- GLCAT.error()
- << "Invalid TextureStage::CombineOperand value" << endl;
- return GL_SRC_COLOR;
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_fog_mode_type
- // Access: Protected, Static
- // Description: Maps from the fog types to gl version
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- get_fog_mode_type(Fog::Mode m) {
- switch(m) {
- case Fog::M_linear: return GL_LINEAR;
- case Fog::M_exponential: return GL_EXP;
- case Fog::M_exponential_squared: return GL_EXP2;
- /*
- case Fog::M_spline: return GL_FOG_FUNC_SGIS;
- */
- default:
- GLCAT.error() << "Invalid Fog::Mode value" << endl;
- return GL_EXP;
- }
- }
- #endif
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_blend_equation_type
- // Access: Protected, Static
- // Description: Maps from ColorBlendAttrib::Mode to glBlendEquation
- // value.
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- get_blend_equation_type(ColorBlendAttrib::Mode mode) {
- switch (mode) {
- case ColorBlendAttrib::M_none:
- case ColorBlendAttrib::M_add:
- return GL_FUNC_ADD;
- case ColorBlendAttrib::M_subtract:
- return GL_FUNC_SUBTRACT;
- case ColorBlendAttrib::M_inv_subtract:
- return GL_FUNC_REVERSE_SUBTRACT;
- #ifdef OPENGLES
- case ColorBlendAttrib::M_min:
- return GL_MIN_EXT;
- case ColorBlendAttrib::M_max:
- return GL_MAX_EXT;
- #else
- case ColorBlendAttrib::M_min:
- return GL_MIN;
- case ColorBlendAttrib::M_max:
- return GL_MAX;
- #endif
- }
- GLCAT.error()
- << "Unknown color blend mode " << (int)mode << endl;
- return GL_FUNC_ADD;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_blend_func
- // Access: Protected, Static
- // Description: Maps from ColorBlendAttrib::Operand to glBlendFunc
- // value.
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- get_blend_func(ColorBlendAttrib::Operand operand) {
- switch (operand) {
- case ColorBlendAttrib::O_zero:
- return GL_ZERO;
- case ColorBlendAttrib::O_one:
- return GL_ONE;
- case ColorBlendAttrib::O_incoming_color:
- return GL_SRC_COLOR;
- case ColorBlendAttrib::O_one_minus_incoming_color:
- return GL_ONE_MINUS_SRC_COLOR;
- case ColorBlendAttrib::O_fbuffer_color:
- return GL_DST_COLOR;
- case ColorBlendAttrib::O_one_minus_fbuffer_color:
- return GL_ONE_MINUS_DST_COLOR;
- case ColorBlendAttrib::O_incoming_alpha:
- return GL_SRC_ALPHA;
- case ColorBlendAttrib::O_one_minus_incoming_alpha:
- return GL_ONE_MINUS_SRC_ALPHA;
- case ColorBlendAttrib::O_fbuffer_alpha:
- return GL_DST_ALPHA;
- case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
- return GL_ONE_MINUS_DST_ALPHA;
- #ifdef OPENGLES_1
- // OpenGL ES 1 has no constant blend factor.
- case ColorBlendAttrib::O_constant_color:
- case ColorBlendAttrib::O_color_scale:
- case ColorBlendAttrib::O_one_minus_constant_color:
- case ColorBlendAttrib::O_one_minus_color_scale:
- case ColorBlendAttrib::O_constant_alpha:
- case ColorBlendAttrib::O_alpha_scale:
- case ColorBlendAttrib::O_one_minus_constant_alpha:
- case ColorBlendAttrib::O_one_minus_alpha_scale:
- break;
- #else
- case ColorBlendAttrib::O_constant_color:
- case ColorBlendAttrib::O_color_scale:
- return GL_CONSTANT_COLOR;
- case ColorBlendAttrib::O_one_minus_constant_color:
- case ColorBlendAttrib::O_one_minus_color_scale:
- return GL_ONE_MINUS_CONSTANT_COLOR;
- case ColorBlendAttrib::O_constant_alpha:
- case ColorBlendAttrib::O_alpha_scale:
- return GL_CONSTANT_ALPHA;
- case ColorBlendAttrib::O_one_minus_constant_alpha:
- case ColorBlendAttrib::O_one_minus_alpha_scale:
- return GL_ONE_MINUS_CONSTANT_ALPHA;
- #endif
- case ColorBlendAttrib::O_incoming_color_saturate:
- return GL_SRC_ALPHA_SATURATE;
- }
- GLCAT.error()
- << "Unknown color blend operand " << (int)operand << endl;
- return GL_ZERO;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_usage
- // Access: Public, Static
- // Description: Maps from UsageHint to the GL symbol.
- ////////////////////////////////////////////////////////////////////
- GLenum CLP(GraphicsStateGuardian)::
- get_usage(Geom::UsageHint usage_hint) {
- switch (usage_hint) {
- case Geom::UH_stream:
- #ifdef OPENGLES
- return GL_DYNAMIC_DRAW;
- #else
- return GL_STREAM_DRAW;
- #endif // OPENGLES
- case Geom::UH_static:
- case Geom::UH_unspecified:
- return GL_STATIC_DRAW;
- case Geom::UH_dynamic:
- return GL_DYNAMIC_DRAW;
- case Geom::UH_client:
- break;
- }
- GLCAT.error()
- << "Unexpected usage_hint " << (int)usage_hint << endl;
- return GL_STATIC_DRAW;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_compressed_format_string
- // Access: Public, Static
- // Description: Returns a string describing an compression format.
- ////////////////////////////////////////////////////////////////////
- const char *CLP(GraphicsStateGuardian)::
- get_compressed_format_string(GLenum format) {
- switch (format) {
- case 0x83F0: return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT";
- case 0x83F1: return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT";
- case 0x83F2: return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT";
- case 0x83F3: return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT";
- case 0x86B0: return "GL_COMPRESSED_RGB_FXT1_3DFX";
- case 0x86B1: return "GL_COMPRESSED_RGBA_FXT1_3DFX";
- case 0x8A54: return "GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT";
- case 0x8A55: return "GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT";
- case 0x8A56: return "GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT";
- case 0x8A57: return "GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT";
- case 0x8B90: return "GL_PALETTE4_RGB8_OES";
- case 0x8B91: return "GL_PALETTE4_RGBA8_OES";
- case 0x8B92: return "GL_PALETTE4_R5_G6_B5_OES";
- case 0x8B93: return "GL_PALETTE4_RGBA4_OES";
- case 0x8B94: return "GL_PALETTE4_RGB5_A1_OES";
- case 0x8B95: return "GL_PALETTE8_RGB8_OES";
- case 0x8B96: return "GL_PALETTE8_RGBA8_OES";
- case 0x8B97: return "GL_PALETTE8_R5_G6_B5_OES";
- case 0x8B98: return "GL_PALETTE8_RGBA4_OES";
- case 0x8B99: return "GL_PALETTE8_RGB5_A1_OES";
- case 0x8C00: return "GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG";
- case 0x8C01: return "GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG";
- case 0x8C02: return "GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG";
- case 0x8C03: return "GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG";
- case 0x8C48: return "GL_COMPRESSED_SRGB_EXT";
- case 0x8C49: return "GL_COMPRESSED_SRGB_ALPHA_EXT";
- case 0x8C4A: return "GL_COMPRESSED_SLUMINANCE_EXT";
- case 0x8C4B: return "GL_COMPRESSED_SLUMINANCE_ALPHA_EXT";
- case 0x8C4C: return "GL_COMPRESSED_SRGB_S3TC_DXT1_EXT";
- case 0x8C4D: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT";
- case 0x8C4E: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT";
- case 0x8C4F: return "GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT";
- case 0x8C70: return "GL_COMPRESSED_LUMINANCE_LATC1_EXT";
- case 0x8C71: return "GL_COMPRESSED_SIGNED_LUMINANCE_LATC1_EXT";
- case 0x8C72: return "GL_COMPRESSED_LUMINANCE_ALPHA_LATC2_EXT";
- case 0x8C73: return "GL_COMPRESSED_SIGNED_LUMINANCE_ALPHA_LATC2_EXT";
- case 0x8DBB: return "GL_COMPRESSED_RED_RGTC1";
- case 0x8DBC: return "GL_COMPRESSED_SIGNED_RED_RGTC1";
- case 0x8DBD: return "GL_COMPRESSED_RG_RGTC2";
- case 0x8DBE: return "GL_COMPRESSED_SIGNED_RG_RGTC2";
- case 0x8E8C: return "GL_COMPRESSED_RGBA_BPTC_UNORM";
- case 0x8E8D: return "GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM";
- case 0x8E8E: return "GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT";
- case 0x8E8F: return "GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT";
- case 0x9137: return "GL_COMPRESSED_RGBA_PVRTC_2BPPV2_IMG";
- case 0x9138: return "GL_COMPRESSED_RGBA_PVRTC_4BPPV2_IMG";
- case 0x9270: return "GL_COMPRESSED_R11_EAC";
- case 0x9271: return "GL_COMPRESSED_SIGNED_R11_EAC";
- case 0x9272: return "GL_COMPRESSED_RG11_EAC";
- case 0x9273: return "GL_COMPRESSED_SIGNED_RG11_EAC";
- case 0x9274: return "GL_COMPRESSED_RGB8_ETC2";
- case 0x9275: return "GL_COMPRESSED_SRGB8_ETC2";
- case 0x9276: return "GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2";
- case 0x9277: return "GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2";
- case 0x9278: return "GL_COMPRESSED_RGBA8_ETC2_EAC";
- case 0x9279: return "GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC";
- case 0x93B0: return "GL_COMPRESSED_RGBA_ASTC_4x4_KHR";
- case 0x93B1: return "GL_COMPRESSED_RGBA_ASTC_5x4_KHR";
- case 0x93B2: return "GL_COMPRESSED_RGBA_ASTC_5x5_KHR";
- case 0x93B3: return "GL_COMPRESSED_RGBA_ASTC_6x5_KHR";
- case 0x93B4: return "GL_COMPRESSED_RGBA_ASTC_6x6_KHR";
- case 0x93B5: return "GL_COMPRESSED_RGBA_ASTC_8x5_KHR";
- case 0x93B6: return "GL_COMPRESSED_RGBA_ASTC_8x6_KHR";
- case 0x93B7: return "GL_COMPRESSED_RGBA_ASTC_8x8_KHR";
- case 0x93B8: return "GL_COMPRESSED_RGBA_ASTC_10x5_KHR";
- case 0x93B9: return "GL_COMPRESSED_RGBA_ASTC_10x6_KHR";
- case 0x93BA: return "GL_COMPRESSED_RGBA_ASTC_10x8_KHR";
- case 0x93BB: return "GL_COMPRESSED_RGBA_ASTC_10x10_KHR";
- case 0x93BC: return "GL_COMPRESSED_RGBA_ASTC_12x10_KHR";
- case 0x93BD: return "GL_COMPRESSED_RGBA_ASTC_12x12_KHR";
- case 0x93C0: return "GL_COMPRESSED_RGBA_ASTC_3x3x3_OES";
- case 0x93C1: return "GL_COMPRESSED_RGBA_ASTC_4x3x3_OES";
- case 0x93C2: return "GL_COMPRESSED_RGBA_ASTC_4x4x3_OES";
- case 0x93C3: return "GL_COMPRESSED_RGBA_ASTC_4x4x4_OES";
- case 0x93C4: return "GL_COMPRESSED_RGBA_ASTC_5x4x4_OES";
- case 0x93C5: return "GL_COMPRESSED_RGBA_ASTC_5x5x4_OES";
- case 0x93C6: return "GL_COMPRESSED_RGBA_ASTC_5x5x5_OES";
- case 0x93C7: return "GL_COMPRESSED_RGBA_ASTC_6x5x5_OES";
- case 0x93C8: return "GL_COMPRESSED_RGBA_ASTC_6x6x5_OES";
- case 0x93C9: return "GL_COMPRESSED_RGBA_ASTC_6x6x6_OES";
- case 0x93D0: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR";
- case 0x93D1: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR";
- case 0x93D2: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR";
- case 0x93D3: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR";
- case 0x93D4: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR";
- case 0x93D5: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR";
- case 0x93D6: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR";
- case 0x93D7: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR";
- case 0x93D8: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR";
- case 0x93D9: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR";
- case 0x93DA: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR";
- case 0x93DB: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR";
- case 0x93DC: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR";
- case 0x93DD: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR";
- case 0x93E0: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_3x3x3_OES";
- case 0x93E1: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x3x3_OES";
- case 0x93E2: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x3_OES";
- case 0x93E3: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4x4_OES";
- case 0x93E4: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4x4_OES";
- case 0x93E5: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x4_OES";
- case 0x93E6: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5x5_OES";
- case 0x93E7: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5x5_OES";
- case 0x93E8: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x5_OES";
- case 0x93E9: return "GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6x6_OES";
- case 0x93F0: return "GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV2_IMG";
- case 0x93F1: return "GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV2_IMG";
- default:
- return NULL;
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_light_color
- // Access: Public
- // Description: Returns the value that that should be issued as the
- // light's color, as scaled by the current value of
- // _light_color_scale, in the case of
- // color_scale_via_lighting.
- ////////////////////////////////////////////////////////////////////
- LVecBase4 CLP(GraphicsStateGuardian)::
- get_light_color(Light *light) const {
- #ifndef NDEBUG
- if (_show_texture_usage) {
- // In show_texture_usage mode, all lights are white, so as not to
- // contaminate the texture color.
- return LVecBase4(1.0, 1.0, 1.0, 1.0);
- }
- #endif // NDEBUG
- const LColor &c = light->get_color();
- LVecBase4 light_color(c[0] * _light_color_scale[0],
- c[1] * _light_color_scale[1],
- c[2] * _light_color_scale[2],
- c[3] * _light_color_scale[3]);
- return light_color;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::reissue_transforms
- // Access: Protected, Virtual
- // Description: Called by clear_state_and_transform() to ensure that
- // the current modelview and projection matrices are
- // properly loaded in the graphics state, after a
- // callback might have mucked them up.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- reissue_transforms() {
- prepare_lens();
- do_issue_transform();
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::enable_lighting
- // Access: Protected, Virtual
- // Description: Intended to be overridden by a derived class to
- // enable or disable the use of lighting overall. This
- // is called by do_issue_light() according to whether any
- // lights are in use or not.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- enable_lighting(bool enable) {
- // static PStatCollector _draw_set_state_light_enable_lighting_pcollector("Draw:Set State:Light:Enable lighting");
- // PStatGPUTimer timer(this, _draw_set_state_light_enable_lighting_pcollector);
- if (enable) {
- glEnable(GL_LIGHTING);
- } else {
- glDisable(GL_LIGHTING);
- }
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::set_ambient_light
- // Access: Protected, Virtual
- // Description: Intended to be overridden by a derived class to
- // indicate the color of the ambient light that should
- // be in effect. This is called by do_issue_light() after
- // all other lights have been enabled or disabled.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- set_ambient_light(const LColor &color) {
- // static PStatCollector _draw_set_state_light_ambient_pcollector("Draw:Set State:Light:Ambient");
- // PStatGPUTimer timer(this, _draw_set_state_light_ambient_pcollector);
- LColor c = color;
- c.set(c[0] * _light_color_scale[0],
- c[1] * _light_color_scale[1],
- c[2] * _light_color_scale[2],
- c[3] * _light_color_scale[3]);
- call_glLightModelfv(GL_LIGHT_MODEL_AMBIENT, c);
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::enable_light
- // Access: Protected, Virtual
- // Description: Intended to be overridden by a derived class to
- // enable the indicated light id. A specific Light will
- // already have been bound to this id via bind_light().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- enable_light(int light_id, bool enable) {
- // static PStatCollector _draw_set_state_light_enable_light_pcollector("Draw:Set State:Light:Enable light");
- // PStatGPUTimer timer(this, _draw_set_state_light_enable_light_pcollector);
- if (enable) {
- glEnable(get_light_id(light_id));
- } else {
- glDisable(get_light_id(light_id));
- }
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::begin_bind_lights
- // Access: Protected, Virtual
- // Description: Called immediately before bind_light() is called,
- // this is intended to provide the derived class a hook
- // in which to set up some state (like transform) that
- // might apply to several lights.
- //
- // The sequence is: begin_bind_lights() will be called,
- // then one or more bind_light() calls, then
- // end_bind_lights().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- begin_bind_lights() {
- // static PStatCollector _draw_set_state_light_begin_bind_pcollector("Draw:Set State:Light:Begin bind");
- // PStatGPUTimer timer(this, _draw_set_state_light_begin_bind_pcollector);
- // We need to temporarily load a new matrix so we can define the
- // light in a known coordinate system. We pick the transform of the
- // root. (Alternatively, we could leave the current transform where
- // it is and compute the light position relative to that transform
- // instead of relative to the root, by composing with the matrix
- // computed by _internal_transform->invert_compose(render_transform).
- // But I think loading a completely new matrix is simpler.)
- CPT(TransformState) render_transform =
- _cs_transform->compose(_scene_setup->get_world_transform());
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- GLPf(LoadMatrix)(render_transform->get_mat().get_data());
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::end_bind_lights
- // Access: Protected, Virtual
- // Description: Called after before bind_light() has been called one
- // or more times (but before any geometry is issued or
- // additional state is changed), this is intended to
- // clean up any temporary changes to the state that may
- // have been made by begin_bind_lights().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- end_bind_lights() {
- // static PStatCollector _draw_set_state_light_end_bind_pcollector("Draw:Set State:Light:End bind");
- // PStatGPUTimer timer(this, _draw_set_state_light_end_bind_pcollector);
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::enable_clip_plane
- // Access: Protected, Virtual
- // Description: Intended to be overridden by a derived class to
- // enable the indicated clip_plane id. A specific
- // PlaneNode will already have been bound to this id via
- // bind_clip_plane().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- enable_clip_plane(int plane_id, bool enable) {
- if (enable) {
- glEnable(get_clip_plane_id(plane_id));
- } else {
- glDisable(get_clip_plane_id(plane_id));
- }
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::begin_bind_clip_planes
- // Access: Protected, Virtual
- // Description: Called immediately before bind_clip_plane() is called,
- // this is intended to provide the derived class a hook
- // in which to set up some state (like transform) that
- // might apply to several clip_planes.
- //
- // The sequence is: begin_bind_clip_planes() will be called,
- // then one or more bind_clip_plane() calls, then
- // end_bind_clip_planes().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- begin_bind_clip_planes() {
- // We need to temporarily load a new matrix so we can define the
- // clip_plane in a known coordinate system. We pick the transform of the
- // root. (Alternatively, we could leave the current transform where
- // it is and compute the clip_plane position relative to that transform
- // instead of relative to the root, by composing with the matrix
- // computed by _internal_transform->invert_compose(render_transform).
- // But I think loading a completely new matrix is simpler.)
- CPT(TransformState) render_transform =
- _cs_transform->compose(_scene_setup->get_world_transform());
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- GLPf(LoadMatrix)(render_transform->get_mat().get_data());
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::bind_clip_plane
- // Access: Protected, Virtual
- // Description: Called the first time a particular clip_plane has been
- // bound to a given id within a frame, this should set
- // up the associated hardware clip_plane with the clip_plane's
- // properties.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- bind_clip_plane(const NodePath &plane, int plane_id) {
- GLenum id = get_clip_plane_id(plane_id);
- CPT(TransformState) transform = plane.get_transform(_scene_setup->get_scene_root().get_parent());
- const PlaneNode *plane_node;
- DCAST_INTO_V(plane_node, plane.node());
- LPlane xformed_plane = plane_node->get_plane() * transform->get_mat();
- #ifdef OPENGLES
- // OpenGL ES uses a single-precision call.
- LPlanef single_plane(LCAST(float, xformed_plane));
- glClipPlanef(id, single_plane.get_data());
- #else
- // Mainline OpenGL uses a double-precision call.
- LPlaned double_plane(LCAST(double, xformed_plane));
- glClipPlane(id, double_plane.get_data());
- #endif // OPENGLES
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::end_bind_clip_planes
- // Access: Protected, Virtual
- // Description: Called after before bind_clip_plane() has been called one
- // or more times (but before any geometry is issued or
- // additional state is changed), this is intended to
- // clean up any temporary changes to the state that may
- // have been made by begin_bind_clip_planes().
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- end_bind_clip_planes() {
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::set_state_and_transform
- // Access: Public, Virtual
- // Description: Simultaneously resets the render state and the
- // transform state.
- //
- // This transform specified is the "internal" net
- // transform, already converted into the GSG's internal
- // coordinate space by composing it to
- // get_cs_transform(). (Previously, this used to be the
- // "external" net transform, with the assumption that
- // that GSG would convert it internally, but that is no
- // longer the case.)
- //
- // Special case: if (state==NULL), then the target
- // state is already stored in _target.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- set_state_and_transform(const RenderState *target,
- const TransformState *transform) {
- report_my_gl_errors();
- #ifndef NDEBUG
- if (gsg_cat.is_spam()) {
- gsg_cat.spam() << "Setting GSG state to " << (void *)target << ":\n";
- target->write(gsg_cat.spam(false), 2);
- }
- #endif
- _state_pcollector.add_level(1);
- PStatGPUTimer timer1(this, _draw_set_state_pcollector);
- if (transform != _internal_transform) {
- //PStatGPUTimer timer(this, _draw_set_state_transform_pcollector);
- _transform_state_pcollector.add_level(1);
- _internal_transform = transform;
- do_issue_transform();
- }
- if (target == _state_rs && (_state_mask | _inv_state_mask).is_all_on()) {
- return;
- }
- _target_rs = target;
- _target_shader = (const ShaderAttrib *)
- _target_rs->get_attrib_def(ShaderAttrib::get_class_slot());
- #ifndef OPENGLES_1
- _instance_count = _target_shader->get_instance_count();
- #endif
- #ifdef SUPPORT_FIXED_FUNCTION
- int alpha_test_slot = AlphaTestAttrib::get_class_slot();
- if (_target_rs->get_attrib(alpha_test_slot) != _state_rs->get_attrib(alpha_test_slot) ||
- !_state_mask.get_bit(alpha_test_slot) ||
- (_target_shader->get_flag(ShaderAttrib::F_subsume_alpha_test) !=
- _state_shader->get_flag(ShaderAttrib::F_subsume_alpha_test))) {
- //PStatGPUTimer timer(this, _draw_set_state_alpha_test_pcollector);
- do_issue_alpha_test();
- _state_mask.set_bit(alpha_test_slot);
- }
- #endif
- int antialias_slot = AntialiasAttrib::get_class_slot();
- if (_target_rs->get_attrib(antialias_slot) != _state_rs->get_attrib(antialias_slot) ||
- !_state_mask.get_bit(antialias_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_antialias_pcollector);
- do_issue_antialias();
- _state_mask.set_bit(antialias_slot);
- }
- int clip_plane_slot = ClipPlaneAttrib::get_class_slot();
- if (_target_rs->get_attrib(clip_plane_slot) != _state_rs->get_attrib(clip_plane_slot) ||
- !_state_mask.get_bit(clip_plane_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_clip_plane_pcollector);
- do_issue_clip_plane();
- _state_mask.set_bit(clip_plane_slot);
- #ifndef OPENGLES_1
- if (_current_shader_context) {
- _current_shader_context->issue_parameters(Shader::SSD_clip_planes);
- }
- #endif
- }
- int color_slot = ColorAttrib::get_class_slot();
- int color_scale_slot = ColorScaleAttrib::get_class_slot();
- if (_target_rs->get_attrib(color_slot) != _state_rs->get_attrib(color_slot) ||
- _target_rs->get_attrib(color_scale_slot) != _state_rs->get_attrib(color_scale_slot) ||
- !_state_mask.get_bit(color_slot) ||
- !_state_mask.get_bit(color_scale_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_color_pcollector);
- do_issue_color();
- do_issue_color_scale();
- _state_mask.set_bit(color_slot);
- _state_mask.set_bit(color_scale_slot);
- #ifndef OPENGLES_1
- if (_current_shader_context) {
- _current_shader_context->issue_parameters(Shader::SSD_color);
- _current_shader_context->issue_parameters(Shader::SSD_colorscale);
- }
- #endif
- }
- int cull_face_slot = CullFaceAttrib::get_class_slot();
- if (_target_rs->get_attrib(cull_face_slot) != _state_rs->get_attrib(cull_face_slot) ||
- !_state_mask.get_bit(cull_face_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_cull_face_pcollector);
- do_issue_cull_face();
- _state_mask.set_bit(cull_face_slot);
- }
- int depth_offset_slot = DepthOffsetAttrib::get_class_slot();
- if (_target_rs->get_attrib(depth_offset_slot) != _state_rs->get_attrib(depth_offset_slot) ||
- !_state_mask.get_bit(depth_offset_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_depth_offset_pcollector);
- do_issue_depth_offset();
- _state_mask.set_bit(depth_offset_slot);
- }
- int depth_test_slot = DepthTestAttrib::get_class_slot();
- if (_target_rs->get_attrib(depth_test_slot) != _state_rs->get_attrib(depth_test_slot) ||
- !_state_mask.get_bit(depth_test_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_depth_test_pcollector);
- do_issue_depth_test();
- _state_mask.set_bit(depth_test_slot);
- }
- int depth_write_slot = DepthWriteAttrib::get_class_slot();
- if (_target_rs->get_attrib(depth_write_slot) != _state_rs->get_attrib(depth_write_slot) ||
- !_state_mask.get_bit(depth_write_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_depth_write_pcollector);
- do_issue_depth_write();
- _state_mask.set_bit(depth_write_slot);
- }
- int render_mode_slot = RenderModeAttrib::get_class_slot();
- if (_target_rs->get_attrib(render_mode_slot) != _state_rs->get_attrib(render_mode_slot) ||
- !_state_mask.get_bit(render_mode_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_render_mode_pcollector);
- do_issue_render_mode();
- _state_mask.set_bit(render_mode_slot);
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- int rescale_normal_slot = RescaleNormalAttrib::get_class_slot();
- if (_target_rs->get_attrib(rescale_normal_slot) != _state_rs->get_attrib(rescale_normal_slot) ||
- !_state_mask.get_bit(rescale_normal_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_rescale_normal_pcollector);
- do_issue_rescale_normal();
- _state_mask.set_bit(rescale_normal_slot);
- }
- #endif
- #ifdef SUPPORT_FIXED_FUNCTION
- int shade_model_slot = ShadeModelAttrib::get_class_slot();
- if (_target_rs->get_attrib(shade_model_slot) != _state_rs->get_attrib(shade_model_slot) ||
- !_state_mask.get_bit(shade_model_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_shade_model_pcollector);
- do_issue_shade_model();
- _state_mask.set_bit(shade_model_slot);
- }
- #endif
- int transparency_slot = TransparencyAttrib::get_class_slot();
- int color_write_slot = ColorWriteAttrib::get_class_slot();
- int color_blend_slot = ColorBlendAttrib::get_class_slot();
- if (_target_rs->get_attrib(transparency_slot) != _state_rs->get_attrib(transparency_slot) ||
- _target_rs->get_attrib(color_write_slot) != _state_rs->get_attrib(color_write_slot) ||
- _target_rs->get_attrib(color_blend_slot) != _state_rs->get_attrib(color_blend_slot) ||
- !_state_mask.get_bit(transparency_slot) ||
- !_state_mask.get_bit(color_write_slot) ||
- !_state_mask.get_bit(color_blend_slot) ||
- (_target_shader->get_flag(ShaderAttrib::F_disable_alpha_write) !=
- _state_shader->get_flag(ShaderAttrib::F_disable_alpha_write))) {
- //PStatGPUTimer timer(this, _draw_set_state_blending_pcollector);
- do_issue_blending();
- _state_mask.set_bit(transparency_slot);
- _state_mask.set_bit(color_write_slot);
- _state_mask.set_bit(color_blend_slot);
- }
- if (_target_shader != _state_shader) {
- //PStatGPUTimer timer(this, _draw_set_state_shader_pcollector);
- #ifndef OPENGLES_1
- do_issue_shader(true);
- #endif
- _state_shader = _target_shader;
- _state_mask.clear_bit(TextureAttrib::get_class_slot());
- }
- #ifndef SUPPORT_FIXED_FUNCTION
- else { // In the case of OpenGL ES 2.x, we need to glUseShader before we draw anything.
- do_issue_shader(false);
- }
- #endif
- int texture_slot = TextureAttrib::get_class_slot();
- if (_target_rs->get_attrib(texture_slot) != _state_rs->get_attrib(texture_slot) ||
- !_state_mask.get_bit(texture_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_texture_pcollector);
- determine_target_texture();
- int prev_active = _num_active_texture_stages;
- do_issue_texture();
- // Since the TexGen and TexMatrix states depend partly on the
- // particular set of textures in use, we should force both of
- // those to be reissued every time we change the texture state.
- _state_mask.clear_bit(TexGenAttrib::get_class_slot());
- _state_mask.clear_bit(TexMatrixAttrib::get_class_slot());
- _state_texture = _target_texture;
- _state_mask.set_bit(texture_slot);
- }
- // If one of the previously-loaded TexGen modes modified the texture
- // matrix, then if either state changed, we have to change both of
- // them now.
- if (_tex_gen_modifies_mat) {
- int tex_gen_slot = TexGenAttrib::get_class_slot();
- int tex_matrix_slot = TexMatrixAttrib::get_class_slot();
- if (_target_rs->get_attrib(tex_gen_slot) != _state_rs->get_attrib(tex_gen_slot) ||
- _target_rs->get_attrib(tex_matrix_slot) != _state_rs->get_attrib(tex_matrix_slot) ||
- !_state_mask.get_bit(tex_gen_slot) ||
- !_state_mask.get_bit(tex_matrix_slot)) {
- _state_mask.clear_bit(tex_gen_slot);
- _state_mask.clear_bit(tex_matrix_slot);
- }
- }
- int tex_matrix_slot = TexMatrixAttrib::get_class_slot();
- if (_target_rs->get_attrib(tex_matrix_slot) != _state_rs->get_attrib(tex_matrix_slot) ||
- !_state_mask.get_bit(tex_matrix_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_tex_matrix_pcollector);
- #ifdef SUPPORT_FIXED_FUNCTION
- do_issue_tex_matrix();
- #endif
- _state_mask.set_bit(tex_matrix_slot);
- #ifndef OPENGLES_1
- if (_current_shader_context) {
- _current_shader_context->issue_parameters(Shader::SSD_tex_matrix);
- }
- #endif
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- int tex_gen_slot = TexGenAttrib::get_class_slot();
- if (_target_tex_gen != _state_tex_gen ||
- !_state_mask.get_bit(tex_gen_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_tex_gen_pcollector);
- do_issue_tex_gen();
- _state_tex_gen = _target_tex_gen;
- _state_mask.set_bit(tex_gen_slot);
- }
- #endif
- int material_slot = MaterialAttrib::get_class_slot();
- if (_target_rs->get_attrib(material_slot) != _state_rs->get_attrib(material_slot) ||
- !_state_mask.get_bit(material_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_material_pcollector);
- #ifdef SUPPORT_FIXED_FUNCTION
- do_issue_material();
- #endif
- _state_mask.set_bit(material_slot);
- #ifndef OPENGLES_1
- if (_current_shader_context) {
- _current_shader_context->issue_parameters(Shader::SSD_material);
- }
- #endif
- }
- int light_slot = LightAttrib::get_class_slot();
- if (_target_rs->get_attrib(light_slot) != _state_rs->get_attrib(light_slot) ||
- !_state_mask.get_bit(light_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_light_pcollector);
- #ifdef SUPPORT_FIXED_FUNCTION
- do_issue_light();
- #endif
- _state_mask.set_bit(light_slot);
- #ifndef OPENGLES_1
- if (_current_shader_context) {
- _current_shader_context->issue_parameters(Shader::SSD_light);
- }
- #endif
- }
- int stencil_slot = StencilAttrib::get_class_slot();
- if (_target_rs->get_attrib(stencil_slot) != _state_rs->get_attrib(stencil_slot) ||
- !_state_mask.get_bit(stencil_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_stencil_pcollector);
- do_issue_stencil();
- _state_mask.set_bit(stencil_slot);
- }
- int fog_slot = FogAttrib::get_class_slot();
- if (_target_rs->get_attrib(fog_slot) != _state_rs->get_attrib(fog_slot) ||
- !_state_mask.get_bit(fog_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_fog_pcollector);
- #ifdef SUPPORT_FIXED_FUNCTION
- do_issue_fog();
- #endif
- _state_mask.set_bit(fog_slot);
- #ifndef OPENGLES_1
- if (_current_shader_context) {
- _current_shader_context->issue_parameters(Shader::SSD_fog);
- }
- #endif
- }
- int scissor_slot = ScissorAttrib::get_class_slot();
- if (_target_rs->get_attrib(scissor_slot) != _state_rs->get_attrib(scissor_slot) ||
- !_state_mask.get_bit(scissor_slot)) {
- //PStatGPUTimer timer(this, _draw_set_state_scissor_pcollector);
- do_issue_scissor();
- _state_mask.set_bit(scissor_slot);
- }
- _state_rs = _target_rs;
- maybe_gl_finish();
- report_my_gl_errors();
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::free_pointers
- // Access: Protected, Virtual
- // Description: Frees some memory that was explicitly allocated
- // within the glgsg.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- free_pointers() {
- #if defined(HAVE_CG) && !defined(OPENGLES)
- if (_cg_context != 0) {
- cgDestroyContext(_cg_context);
- _cg_context = 0;
- }
- #endif
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_texture
- // Access: Protected, Virtual
- // Description: This is called by set_state_and_transform() when
- // the texture state has changed.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_texture() {
- DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
- #ifdef OPENGLES_1
- update_standard_texture_bindings();
- #else
- if (_current_shader_context == 0 || !_current_shader_context->uses_custom_texture_bindings()) {
- // No shader, or a non-Cg shader.
- if (_texture_binding_shader_context != 0) {
- _texture_binding_shader_context->disable_shader_texture_bindings();
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- update_standard_texture_bindings();
- #endif
- } else {
- if (_texture_binding_shader_context == 0) {
- #ifdef SUPPORT_FIXED_FUNCTION
- disable_standard_texture_bindings();
- #endif
- _current_shader_context->update_shader_texture_bindings(NULL);
- } else {
- _current_shader_context->
- update_shader_texture_bindings(_texture_binding_shader_context);
- }
- }
- _texture_binding_shader = _current_shader;
- _texture_binding_shader_context = _current_shader_context;
- #endif
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::update_standard_texture_bindings
- // Access: Private
- // Description: Applies the appropriate set of textures for the
- // current state, using the standard fixed-function
- // pipeline.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- update_standard_texture_bindings() {
- #ifndef NDEBUG
- if (_show_texture_usage) {
- update_show_usage_texture_bindings(-1);
- return;
- }
- #endif // NDEBUG
- int num_stages = _target_texture->get_num_on_ff_stages();
- #ifndef NDEBUG
- // Also check the _flash_texture. If it is non-NULL, we need to
- // check to see if our flash_texture is in the texture stack here.
- // If so, then we need to call the special show_texture method
- // instead of the normal texture stack.
- if (_flash_texture != (Texture *)NULL) {
- double now = ClockObject::get_global_clock()->get_frame_time();
- int this_second = (int)floor(now);
- if (this_second & 1) {
- int show_stage_index = -1;
- for (int i = 0; i < num_stages && show_stage_index < 0; ++i) {
- TextureStage *stage = _target_texture->get_on_ff_stage(i);
- Texture *texture = _target_texture->get_on_texture(stage);
- if (texture == _flash_texture) {
- show_stage_index = i;
- }
- }
- if (show_stage_index >= 0) {
- update_show_usage_texture_bindings(show_stage_index);
- return;
- }
- }
- }
- #endif // NDEBUG
- nassertv(num_stages <= _max_texture_stages &&
- _num_active_texture_stages <= _max_texture_stages);
- _texture_involves_color_scale = false;
- int last_saved_result = -1;
- int last_stage = -1;
- int i;
- for (i = 0; i < num_stages; i++) {
- TextureStage *stage = _target_texture->get_on_ff_stage(i);
- Texture *texture = _target_texture->get_on_texture(stage);
- nassertv(texture != (Texture *)NULL);
- // Issue the texture on stage i.
- _glActiveTexture(GL_TEXTURE0 + i);
- // First, turn off the previous texture mode.
- glDisable(GL_TEXTURE_2D);
- if (_supports_cube_map) {
- glDisable(GL_TEXTURE_CUBE_MAP);
- }
- #ifndef OPENGLES
- glDisable(GL_TEXTURE_1D);
- if (_supports_3d_texture) {
- glDisable(GL_TEXTURE_3D);
- }
- #endif // OPENGLES
- int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
- TextureContext *tc = texture->prepare_now(view, _prepared_objects, this);
- if (tc == (TextureContext *)NULL) {
- // Something wrong with this texture; skip it.
- continue;
- }
- // Then, turn on the current texture mode.
- GLenum target = get_texture_target(texture->get_texture_type());
- if (target == GL_NONE) {
- // Unsupported texture mode.
- continue;
- }
- #ifndef OPENGLES
- if (target == GL_TEXTURE_2D_ARRAY_EXT) {
- // Cannot be applied via the FFP.
- continue;
- }
- #endif // OPENGLES
- glEnable(target);
- if (!update_texture(tc, false)) {
- glDisable(target);
- continue;
- }
- // Don't DCAST(); we already did the verification in update_texture.
- CLP(TextureContext) *gtc = (CLP(TextureContext) *)tc;
- apply_texture(gtc);
- apply_sampler(i, _target_texture->get_on_sampler(stage), gtc);
- if (stage->involves_color_scale() && _color_scale_enabled) {
- LColor color = stage->get_color();
- color.set(color[0] * _current_color_scale[0],
- color[1] * _current_color_scale[1],
- color[2] * _current_color_scale[2],
- color[3] * _current_color_scale[3]);
- _texture_involves_color_scale = true;
- call_glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color);
- } else {
- call_glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, stage->get_color());
- }
- if (stage->get_mode() == TextureStage::M_decal) {
- if (texture->get_num_components() < 3 && _supports_texture_combine) {
- // Make a special case for 1- and 2-channel decal textures.
- // OpenGL does not define their use with GL_DECAL for some
- // reason, so implement them using the combiner instead.
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
- glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
- } else {
- // Normal 3- and 4-channel decal textures.
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
- }
- } else if (stage->get_mode() == TextureStage::M_combine) {
- if (!_supports_texture_combine) {
- GLCAT.warning()
- << "TextureStage::M_combine mode is not supported.\n";
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- } else {
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
- glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE, stage->get_rgb_scale());
- glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, stage->get_alpha_scale());
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB,
- get_texture_combine_type(stage->get_combine_rgb_mode()));
- switch (stage->get_num_combine_rgb_operands()) {
- case 3:
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_RGB,
- get_texture_src_type(stage->get_combine_rgb_source2(),
- last_stage, last_saved_result, i));
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB,
- get_texture_operand_type(stage->get_combine_rgb_operand2()));
- // fall through
- case 2:
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_RGB,
- get_texture_src_type(stage->get_combine_rgb_source1(),
- last_stage, last_saved_result, i));
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB,
- get_texture_operand_type(stage->get_combine_rgb_operand1()));
- // fall through
- case 1:
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_RGB,
- get_texture_src_type(stage->get_combine_rgb_source0(),
- last_stage, last_saved_result, i));
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB,
- get_texture_operand_type(stage->get_combine_rgb_operand0()));
- // fall through
- default:
- break;
- }
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA,
- get_texture_combine_type(stage->get_combine_alpha_mode()));
- switch (stage->get_num_combine_alpha_operands()) {
- case 3:
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC2_ALPHA,
- get_texture_src_type(stage->get_combine_alpha_source2(),
- last_stage, last_saved_result, i));
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA,
- get_texture_operand_type(stage->get_combine_alpha_operand2()));
- // fall through
- case 2:
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC1_ALPHA,
- get_texture_src_type(stage->get_combine_alpha_source1(),
- last_stage, last_saved_result, i));
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA,
- get_texture_operand_type(stage->get_combine_alpha_operand1()));
- // fall through
- case 1:
- glTexEnvi(GL_TEXTURE_ENV, GL_SRC0_ALPHA,
- get_texture_src_type(stage->get_combine_alpha_source0(),
- last_stage, last_saved_result, i));
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA,
- get_texture_operand_type(stage->get_combine_alpha_operand0()));
- // fall through
- default:
- break;
- }
- }
- } else {
- GLint glmode = get_texture_apply_mode_type(stage->get_mode());
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, glmode);
- }
- if (stage->get_saved_result()) {
- // This texture's result will be "saved" for a future stage's
- // input.
- last_saved_result = i;
- } else {
- // This is a regular texture stage; it will be the "previous"
- // input for the next stage.
- last_stage = i;
- }
- }
- // Disable the texture stages that are no longer used.
- for (i = num_stages; i < _num_active_texture_stages; i++) {
- _glActiveTexture(GL_TEXTURE0 + i);
- glDisable(GL_TEXTURE_2D);
- if (_supports_cube_map) {
- glDisable(GL_TEXTURE_CUBE_MAP);
- }
- #ifndef OPENGLES
- glDisable(GL_TEXTURE_1D);
- if (_supports_3d_texture) {
- glDisable(GL_TEXTURE_3D);
- }
- #endif // OPENGLES
- }
- // Save the count of texture stages for next time.
- _num_active_texture_stages = num_stages;
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::apply_white_texture
- // Access: Private
- // Description: Applies a white dummy texture. This is useful to
- // bind to a texture slot when a texture is missing.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- apply_white_texture() {
- if (_white_texture != 0) {
- glBindTexture(GL_TEXTURE_2D, _white_texture);
- return;
- }
- glGenTextures(1, &_white_texture);
- glBindTexture(GL_TEXTURE_2D, _white_texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- unsigned char data[] = {0xff, 0xff, 0xff, 0xff};
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, data);
- }
- #ifndef NDEBUG
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::update_show_usage_texture_bindings
- // Access: Private
- // Description: This is a special function that loads the usage
- // textures in gl-show-texture-usage mode, instead of
- // loading the actual used textures.
- //
- // If the indicated stage_index is >= 0, then it is the
- // particular texture that is shown. Otherwise, the
- // textures are rotated through based on
- // show_texture_usage_index.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- update_show_usage_texture_bindings(int show_stage_index) {
- int num_stages = _target_texture->get_num_on_ff_stages();
- nassertv(num_stages <= _max_texture_stages &&
- _num_active_texture_stages <= _max_texture_stages);
- _texture_involves_color_scale = false;
- // First, we walk through the list of textures and pretend to render
- // them all, even though we don't actually render them, just so
- // Panda will keep track of the list of "active" textures correctly
- // during the flash.
- int i;
- for (i = 0; i < num_stages; i++) {
- TextureStage *stage = _target_texture->get_on_ff_stage(i);
- Texture *texture = _target_texture->get_on_texture(stage);
- nassertv(texture != (Texture *)NULL);
- int view = get_current_tex_view_offset() + stage->get_tex_view_offset();
- TextureContext *tc = texture->prepare_now(view, _prepared_objects, this);
- if (tc == (TextureContext *)NULL) {
- // Something wrong with this texture; skip it.
- break;
- }
- tc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
- }
- #ifdef SUPPORT_FIXED_FUNCTION
- // Disable all texture stages.
- for (i = 0; i < _num_active_texture_stages; i++) {
- _glActiveTexture(GL_TEXTURE0 + i);
- #ifndef OPENGLES
- glDisable(GL_TEXTURE_1D);
- #endif // OPENGLES
- glDisable(GL_TEXTURE_2D);
- if (_supports_3d_texture) {
- #ifndef OPENGLES_1
- glDisable(GL_TEXTURE_3D);
- #endif // OPENGLES_1
- }
- if (_supports_cube_map) {
- glDisable(GL_TEXTURE_CUBE_MAP);
- }
- }
- #endif
- // Save the count of texture stages for next time.
- _num_active_texture_stages = num_stages;
- if (num_stages > 0) {
- // Now, pick just one texture stage to apply.
- if (show_stage_index >= 0 && show_stage_index < num_stages) {
- i = show_stage_index;
- } else {
- i = _show_texture_usage_index % num_stages;
- }
- TextureStage *stage = _target_texture->get_on_ff_stage(i);
- Texture *texture = _target_texture->get_on_texture(stage);
- nassertv(texture != (Texture *)NULL);
- // Choose the corresponding usage texture and apply it.
- _glActiveTexture(GL_TEXTURE0 + i);
- #ifdef SUPPORT_FIXED_FUNCTION
- glEnable(GL_TEXTURE_2D);
- #endif
- UsageTextureKey key(texture->get_x_size(), texture->get_y_size());
- UsageTextures::iterator ui = _usage_textures.find(key);
- if (ui == _usage_textures.end()) {
- // Need to create a new texture for this size.
- GLuint index;
- glGenTextures(1, &index);
- glBindTexture(GL_TEXTURE_2D, index);
- //TODO: this could be a lot simpler with glTexStorage2D
- // followed by a call to glClearTexImage.
- upload_usage_texture(texture->get_x_size(), texture->get_y_size());
- _usage_textures[key] = index;
- } else {
- // Just bind the previously-created texture.
- GLuint index = (*ui).second;
- glBindTexture(GL_TEXTURE_2D, index);
- }
- //TODO: glBindSampler(0) ?
- }
- report_my_gl_errors();
- }
- #endif // NDEBUG
- #ifndef NDEBUG
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::upload_usage_texture
- // Access: Protected
- // Description: Uploads a special "usage" texture intended to be
- // applied only in gl-show-texture-usage mode, to reveal
- // where texture memory is being spent.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- upload_usage_texture(int width, int height) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "upload_usage_texture(" << width << ", " << height << ")\n";
- }
- static LColor colors[3] = {
- LColor(0.4, 0.5f, 0.8f, 1.0f), // mipmap 0: blue
- LColor(1.0f, 1.0f, 0.0f, 1.0f), // mipmap 1: yellow
- LColor(0.8f, 0.3, 0.3, 1.0f), // mipmap 2 and higher: red
- };
- // Allocate a temporary array large enough to contain the toplevel
- // mipmap.
- PN_uint32 *buffer = (PN_uint32 *)PANDA_MALLOC_ARRAY(width * height * 4);
- int n = 0;
- while (true) {
- // Choose the color for the nth mipmap.
- LColor c = colors[min(n, 2)];
- // A simple union to store the colors values bytewise, and get the
- // answer wordwise, independently of machine byte-ordernig.
- union {
- struct {
- unsigned char r, g, b, a;
- } b;
- PN_uint32 w;
- } store;
- store.b.r = (unsigned char)(c[0] * 255.0f);
- store.b.g = (unsigned char)(c[1] * 255.0f);
- store.b.b = (unsigned char)(c[2] * 255.0f);
- store.b.a = 0xff;
- // Fill in the array.
- int num_pixels = width * height;
- for (int p = 0; p < num_pixels; ++p) {
- buffer[p] = store.w;
- }
- glTexImage2D(GL_TEXTURE_2D, n, GL_RGBA, width, height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, buffer);
- if (width == 1 && height == 1) {
- // That was the last mipmap level.
- break;
- }
- width = max(width >> 1, 1);
- height = max(height >> 1, 1);
- ++n;
- }
- PANDA_FREE_ARRAY(buffer);
- }
- #endif // NDEBUG
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::disable_standard_texture_bindings
- // Access: Private
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- disable_standard_texture_bindings() {
- // Disable the texture stages that are no longer used.
- for (int i = 0; i < _num_active_texture_stages; i++) {
- _glActiveTexture(GL_TEXTURE0 + i);
- #ifndef OPENGLES
- glDisable(GL_TEXTURE_1D);
- #endif // OPENGLES
- glDisable(GL_TEXTURE_2D);
- if (_supports_3d_texture) {
- #ifndef OPENGLES_1
- glDisable(GL_TEXTURE_3D);
- #endif // OPENGLES_1
- }
- if (_supports_cube_map) {
- glDisable(GL_TEXTURE_CUBE_MAP);
- }
- }
- _num_active_texture_stages = 0;
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_tex_matrix
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_tex_matrix() {
- nassertv(_num_active_texture_stages <= _max_texture_stages);
- for (int i = 0; i < _num_active_texture_stages; i++) {
- TextureStage *stage = _target_texture->get_on_ff_stage(i);
- _glActiveTexture(GL_TEXTURE0 + i);
- glMatrixMode(GL_TEXTURE);
- const TexMatrixAttrib *target_tex_matrix;
- _target_rs->get_attrib_def(target_tex_matrix);
- if (target_tex_matrix->has_stage(stage)) {
- GLPf(LoadMatrix)(target_tex_matrix->get_mat(stage).get_data());
- } else {
- glLoadIdentity();
- // For some reason, the glLoadIdentity() call doesn't work on
- // my Dell laptop's IBM OpenGL driver, when used in
- // conjunction with glTexGen(), below. But explicitly loading
- // an identity matrix does work. But this buggy-driver
- // workaround might have other performance implications, so I
- // leave it out.
- // GLPf(LoadMatrix)(LMatrix4::ident_mat().get_data());
- }
- }
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- #ifdef SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_tex_gen
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_tex_gen() {
- bool force_normal = false;
- nassertv(_num_active_texture_stages <= _max_texture_stages);
- // These are passed in for the four OBJECT_PLANE or EYE_PLANE
- // values; they effectively define an identity matrix that maps
- // the spatial coordinates one-for-one to UV's. If you want a
- // mapping other than identity, use a TexMatrixAttrib (or a
- // TexProjectorEffect).
- static const PN_stdfloat s_data[4] = { 1, 0, 0, 0 };
- static const PN_stdfloat t_data[4] = { 0, 1, 0, 0 };
- static const PN_stdfloat r_data[4] = { 0, 0, 1, 0 };
- static const PN_stdfloat q_data[4] = { 0, 0, 0, 1 };
- _tex_gen_modifies_mat = false;
- bool got_point_sprites = false;
- for (int i = 0; i < _num_active_texture_stages; i++) {
- TextureStage *stage = _target_texture->get_on_ff_stage(i);
- _glActiveTexture(GL_TEXTURE0 + i);
- if (_supports_point_sprite) {
- #ifdef OPENGLES
- glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_FALSE);
- #else
- glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
- #endif // OPENGLES
- }
- #ifndef OPENGLES // TexGen not supported by OpenGL ES.
- glDisable(GL_TEXTURE_GEN_S);
- glDisable(GL_TEXTURE_GEN_T);
- glDisable(GL_TEXTURE_GEN_R);
- glDisable(GL_TEXTURE_GEN_Q);
- TexGenAttrib::Mode mode = _target_tex_gen->get_mode(stage);
- switch (mode) {
- case TexGenAttrib::M_off:
- case TexGenAttrib::M_unused2:
- break;
- case TexGenAttrib::M_eye_sphere_map:
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- force_normal = true;
- break;
- case TexGenAttrib::M_eye_cube_map:
- if (_supports_cube_map) {
- // We need to rotate the normals out of GL's coordinate
- // system and into the user's coordinate system. We do this
- // by composing a transform onto the texture matrix.
- LMatrix4 mat = _inv_cs_transform->get_mat();
- mat.set_row(3, LVecBase3(0.0f, 0.0f, 0.0f));
- glMatrixMode(GL_TEXTURE);
- GLPf(MultMatrix)(mat.get_data());
- // Now we need to reset the texture matrix next time
- // around to undo this.
- _tex_gen_modifies_mat = true;
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
- glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- glEnable(GL_TEXTURE_GEN_R);
- force_normal = true;
- }
- break;
- case TexGenAttrib::M_world_cube_map:
- if (_supports_cube_map) {
- // We dynamically transform normals from eye space to world
- // space by applying the appropriate rotation transform to
- // the current texture matrix. Unlike M_world_position, we
- // can't achieve this effect by monkeying with the modelview
- // transform, since the current modelview doesn't affect
- // GL_REFLECTION_MAP.
- CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
- LMatrix4 mat = camera_transform->get_mat();
- mat.set_row(3, LVecBase3(0.0f, 0.0f, 0.0f));
- glMatrixMode(GL_TEXTURE);
- GLPf(MultMatrix)(mat.get_data());
- // Now we need to reset the texture matrix next time
- // around to undo this.
- _tex_gen_modifies_mat = true;
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
- glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- glEnable(GL_TEXTURE_GEN_R);
- force_normal = true;
- }
- break;
- case TexGenAttrib::M_eye_normal:
- if (_supports_cube_map) {
- // We need to rotate the normals out of GL's coordinate
- // system and into the user's coordinate system. We do this
- // by composing a transform onto the texture matrix.
- LMatrix4 mat = _inv_cs_transform->get_mat();
- mat.set_row(3, LVecBase3(0.0f, 0.0f, 0.0f));
- glMatrixMode(GL_TEXTURE);
- GLPf(MultMatrix)(mat.get_data());
- // Now we need to reset the texture matrix next time
- // around to undo this.
- _tex_gen_modifies_mat = true;
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
- glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- glEnable(GL_TEXTURE_GEN_R);
- force_normal = true;
- }
- break;
- case TexGenAttrib::M_world_normal:
- if (_supports_cube_map) {
- // We dynamically transform normals from eye space to world
- // space by applying the appropriate rotation transform to
- // the current texture matrix. Unlike M_world_position, we
- // can't achieve this effect by monkeying with the modelview
- // transform, since the current modelview doesn't affect
- // GL_NORMAL_MAP.
- CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
- LMatrix4 mat = camera_transform->get_mat();
- mat.set_row(3, LVecBase3(0.0f, 0.0f, 0.0f));
- glMatrixMode(GL_TEXTURE);
- GLPf(MultMatrix)(mat.get_data());
- // Now we need to reset the texture matrix next time
- // around to undo this.
- _tex_gen_modifies_mat = true;
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
- glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- glEnable(GL_TEXTURE_GEN_R);
- force_normal = true;
- }
- break;
- case TexGenAttrib::M_eye_position:
- // To represent eye position correctly, we need to temporarily
- // load the coordinate-system transform.
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- GLPf(LoadMatrix)(_cs_transform->get_mat().get_data());
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
- glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
- glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
- GLPfv(TexGen)(GL_S, GL_EYE_PLANE, s_data);
- GLPfv(TexGen)(GL_T, GL_EYE_PLANE, t_data);
- GLPfv(TexGen)(GL_R, GL_EYE_PLANE, r_data);
- GLPfv(TexGen)(GL_Q, GL_EYE_PLANE, q_data);
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- glEnable(GL_TEXTURE_GEN_R);
- glEnable(GL_TEXTURE_GEN_Q);
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- break;
- case TexGenAttrib::M_world_position:
- // We achieve world position coordinates by using the eye
- // position mode, and loading the transform of the root
- // node--thus putting the "eye" at the root.
- {
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- CPT(TransformState) root_transform = _cs_transform->compose(_scene_setup->get_world_transform());
- GLPf(LoadMatrix)(root_transform->get_mat().get_data());
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
- glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
- glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
- GLPfv(TexGen)(GL_S, GL_EYE_PLANE, s_data);
- GLPfv(TexGen)(GL_T, GL_EYE_PLANE, t_data);
- GLPfv(TexGen)(GL_R, GL_EYE_PLANE, r_data);
- GLPfv(TexGen)(GL_Q, GL_EYE_PLANE, q_data);
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- glEnable(GL_TEXTURE_GEN_R);
- glEnable(GL_TEXTURE_GEN_Q);
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
- break;
- case TexGenAttrib::M_point_sprite:
- if (_supports_point_sprite) {
- #ifdef OPENGLES
- glTexEnvi(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
- #else
- glTexEnvi(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
- #endif
- got_point_sprites = true;
- }
- break;
- case TexGenAttrib::M_constant:
- // To generate a constant UV(w) coordinate everywhere, we use
- // EYE_LINEAR mode, but we construct a special matrix that
- // flattens the vertex position to zero and then adds our
- // desired value.
- {
- const LTexCoord3 &v = _target_tex_gen->get_constant_value(stage);
- glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
- glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
- glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
- glTexGeni(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
- LVecBase4 s(0.0f, 0.0f, 0.0f, v[0]);
- LVecBase4 t(0.0f, 0.0f, 0.0f, v[1]);
- LVecBase4 r(0.0f, 0.0f, 0.0f, v[2]);
- GLPfv(TexGen)(GL_S, GL_OBJECT_PLANE, s.get_data());
- GLPfv(TexGen)(GL_T, GL_OBJECT_PLANE, t.get_data());
- GLPfv(TexGen)(GL_R, GL_OBJECT_PLANE, r.get_data());
- GLPfv(TexGen)(GL_Q, GL_OBJECT_PLANE, q_data);
- glEnable(GL_TEXTURE_GEN_S);
- glEnable(GL_TEXTURE_GEN_T);
- glEnable(GL_TEXTURE_GEN_R);
- glEnable(GL_TEXTURE_GEN_Q);
- }
- break;
- case TexGenAttrib::M_unused:
- break;
- }
- #endif // OPENGLES
- }
- if (got_point_sprites != _tex_gen_point_sprite) {
- _tex_gen_point_sprite = got_point_sprites;
- #ifdef OPENGLES
- if (_tex_gen_point_sprite) {
- glEnable(GL_POINT_SPRITE_OES);
- } else {
- glDisable(GL_POINT_SPRITE_OES);
- }
- #else
- if (_tex_gen_point_sprite) {
- glEnable(GL_POINT_SPRITE_ARB);
- } else {
- glDisable(GL_POINT_SPRITE_ARB);
- }
- #endif // OPENGLES
- }
- report_my_gl_errors();
- }
- #endif // SUPPORT_FIXED_FUNCTION
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::specify_texture
- // Access: Protected
- // Description: Specifies the texture parameters. Returns true if
- // the texture may need to be reloaded. Pass non-NULL
- // sampler argument to use different sampler settings.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler) {
- nassertr(gtc->_handle == 0 /* can't modify tex with active handle */, false);
- Texture *tex = gtc->get_texture();
- GLenum target = get_texture_target(tex->get_texture_type());
- if (target == GL_NONE) {
- // Unsupported target (e.g. 3-d texturing on GL 1.1).
- return false;
- }
- #ifndef OPENGLES
- if (target == GL_TEXTURE_BUFFER) {
- // Buffer textures may not receive texture parameters.
- return false;
- }
- #endif // OPENGLES
- // Record the active sampler settings.
- gtc->_active_sampler = sampler;
- glTexParameteri(target, GL_TEXTURE_WRAP_S,
- get_texture_wrap_mode(sampler.get_wrap_u()));
- #ifndef OPENGLES
- if (target != GL_TEXTURE_1D) {
- glTexParameteri(target, GL_TEXTURE_WRAP_T,
- get_texture_wrap_mode(sampler.get_wrap_v()));
- }
- #endif
- #ifdef OPENGLES_2
- if (target == GL_TEXTURE_3D_OES) {
- glTexParameteri(target, GL_TEXTURE_WRAP_R_OES,
- get_texture_wrap_mode(sampler.get_wrap_w()));
- }
- #endif
- #ifndef OPENGLES
- if (target == GL_TEXTURE_3D) {
- glTexParameteri(target, GL_TEXTURE_WRAP_R,
- get_texture_wrap_mode(sampler.get_wrap_w()));
- }
- LColor border_color = sampler.get_border_color();
- call_glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, border_color);
- #endif // OPENGLES
- SamplerState::FilterType minfilter = sampler.get_effective_minfilter();
- SamplerState::FilterType magfilter = sampler.get_effective_magfilter();
- bool uses_mipmaps = SamplerState::is_mipmap(minfilter) && !gl_ignore_mipmaps;
- #ifndef NDEBUG
- if (gl_force_mipmaps) {
- minfilter = SamplerState::FT_linear_mipmap_linear;
- magfilter = SamplerState::FT_linear;
- uses_mipmaps = true;
- }
- #endif
- if (!tex->might_have_ram_image()) {
- // If it's a dynamically generated texture (that is, the RAM image
- // isn't available so it didn't pass through the CPU), we should
- // enable GL-generated mipmaps if we can.
- if (!_supports_generate_mipmap) {
- // However, if the GPU doesn't support mipmap generation, we
- // have to turn it off.
- uses_mipmaps = false;
- }
- }
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER,
- get_texture_filter_type(minfilter, !uses_mipmaps));
- glTexParameteri(target, GL_TEXTURE_MAG_FILTER,
- get_texture_filter_type(magfilter, true));
- // Set anisotropic filtering.
- if (_supports_anisotropy) {
- PN_stdfloat anisotropy = sampler.get_effective_anisotropic_degree();
- anisotropy = min(anisotropy, _max_anisotropy);
- anisotropy = max(anisotropy, (PN_stdfloat)1.0);
- glTexParameterf(target, GL_TEXTURE_MAX_ANISOTROPY_EXT, anisotropy);
- }
- #ifndef OPENGLES_1
- if (tex->get_format() == Texture::F_depth_stencil ||
- tex->get_format() == Texture::F_depth_component ||
- tex->get_format() == Texture::F_depth_component16 ||
- tex->get_format() == Texture::F_depth_component24 ||
- tex->get_format() == Texture::F_depth_component32) {
- #ifdef SUPPORT_FIXED_FUNCTION
- glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_INTENSITY);
- #endif
- if (_supports_shadow_filter) {
- if ((sampler.get_magfilter() == SamplerState::FT_shadow) ||
- (sampler.get_minfilter() == SamplerState::FT_shadow)) {
- glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
- glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- } else {
- glTexParameteri(target, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- glTexParameteri(target, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- }
- }
- }
- #endif
- #ifndef OPENGLES
- glTexParameterf(target, GL_TEXTURE_MIN_LOD, sampler.get_min_lod());
- glTexParameterf(target, GL_TEXTURE_MAX_LOD, sampler.get_max_lod());
- glTexParameterf(target, GL_TEXTURE_LOD_BIAS, sampler.get_lod_bias());
- #endif
- report_my_gl_errors();
- if (uses_mipmaps && !gtc->_uses_mipmaps) {
- // Suddenly we require mipmaps. This means the texture may need
- // reloading.
- return true;
- }
- return false;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::apply_texture
- // Access: Protected
- // Description: Updates OpenGL with the current information for this
- // texture, and makes it the current texture available
- // for rendering.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- apply_texture(CLP(TextureContext) *gtc) {
- gtc->set_active(true);
- GLenum target = get_texture_target(gtc->get_texture()->get_texture_type());
- if (target == GL_NONE) {
- return false;
- }
- if (gtc->_target != target) {
- // The target has changed. That means we have to re-bind a new
- // texture object.
- gtc->reset_data();
- gtc->_target = target;
- }
- glBindTexture(target, gtc->_index);
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::apply_sampler
- // Access: Protected
- // Description: Updates OpenGL with the current information for this
- // sampler, and makes it the current sampler available
- // for rendering. Use NULL to unbind the sampler.
- //
- // If the GSG doesn't support sampler objects, the
- // sampler settings are applied to the given texture
- // context instead.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- apply_sampler(GLuint unit, const SamplerState &sampler, CLP(TextureContext) *gtc) {
- #ifndef OPENGLES
- if (_supports_sampler_objects) {
- // We support sampler objects. Prepare the sampler object and
- // bind it to the indicated texture unit.
- SamplerContext *sc = sampler.prepare_now(get_prepared_objects(), this);
- nassertr(sc != (SamplerContext *)NULL, false);
- CLP(SamplerContext) *gsc = DCAST(CLP(SamplerContext), sc);
- gsc->enqueue_lru(&_prepared_objects->_sampler_object_lru);
- _glBindSampler(unit, gsc->_index);
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "bind " << unit << " " << sampler << "\n";
- }
- } else
- #endif // OPENGLES
- {
- // We don't support sampler objects. We'll have to bind the
- // texture and change the texture parameters if they don't match.
- if (gtc->_active_sampler != sampler) {
- _glActiveTexture(GL_TEXTURE0 + unit);
- apply_texture(gtc);
- specify_texture(gtc, sampler);
- }
- }
- if (sampler.uses_mipmaps() && !gtc->_uses_mipmaps) {
- // The texture wasn't created with mipmaps, but we are trying
- // to sample it with mipmaps. We will need to reload it.
- apply_texture(gtc);
- gtc->mark_needs_reload();
- bool okflag = upload_texture(gtc, false, true);
- if (!okflag) {
- GLCAT.error()
- << "Could not load " << *gtc->get_texture() << "\n";
- return false;
- }
- }
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::upload_texture
- // Access: Protected
- // Description: Uploads the entire texture image to OpenGL, including
- // all pages.
- //
- // The return value is true if successful, or false if
- // the texture has no image.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps) {
- PStatGPUTimer timer(this, _load_texture_pcollector);
- Texture *tex = gtc->get_texture();
- if (_effective_incomplete_render && !force) {
- bool has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
- if (!has_image && tex->might_have_ram_image() &&
- tex->has_simple_ram_image() &&
- !_loader.is_null()) {
- // If we don't have the texture data right now, go get it, but in
- // the meantime load a temporary simple image in its place.
- async_reload_texture(gtc);
- has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
- if (!has_image) {
- if (gtc->was_simple_image_modified()) {
- return upload_simple_texture(gtc);
- }
- return true;
- }
- }
- }
- CPTA_uchar image;
- if (_supports_compressed_texture) {
- image = tex->get_ram_image();
- } else {
- image = tex->get_uncompressed_ram_image();
- }
- Texture::CompressionMode image_compression;
- if (image.is_null()) {
- image_compression = Texture::CM_off;
- } else {
- image_compression = tex->get_ram_image_compression();
- }
- if (!get_supports_compressed_texture_format(image_compression)) {
- image = tex->get_uncompressed_ram_image();
- image_compression = Texture::CM_off;
- }
- int mipmap_bias = 0;
- int width = tex->get_x_size();
- int height = tex->get_y_size();
- int depth = tex->get_z_size();
- // If we'll use immutable texture storage, we have to pick a sized
- // image format.
- bool force_sized = (gl_immutable_texture_storage && _supports_tex_storage) ||
- (tex->get_texture_type() == Texture::TT_buffer_texture);
- GLint internal_format = get_internal_image_format(tex, force_sized);
- GLint external_format = get_external_image_format(tex);
- GLenum component_type = get_component_type(tex->get_component_type());
- if (GLCAT.is_debug()) {
- if (image.is_null()) {
- GLCAT.debug()
- << "loading texture with NULL image";
- } else if (image_compression != Texture::CM_off) {
- GLCAT.debug()
- << "loading pre-compressed texture";
- } else if (is_compressed_format(internal_format)) {
- GLCAT.debug()
- << "loading compressed texture";
- } else {
- GLCAT.debug()
- << "loading uncompressed texture";
- }
- GLCAT.debug(false) << " " << tex->get_name() << "\n";
- }
- // Ensure that the texture fits within the GL's specified limits.
- // Need to split dimensions because of texture arrays
- int max_dimension_x;
- int max_dimension_y;
- int max_dimension_z;
- switch (tex->get_texture_type()) {
- case Texture::TT_3d_texture:
- max_dimension_x = _max_3d_texture_dimension;
- max_dimension_y = _max_3d_texture_dimension;
- max_dimension_z = _max_3d_texture_dimension;
- break;
- case Texture::TT_cube_map:
- max_dimension_x = _max_cube_map_dimension;
- max_dimension_y = _max_cube_map_dimension;
- max_dimension_z = 6;
- break;
- case Texture::TT_2d_texture_array:
- max_dimension_x = _max_texture_dimension;
- max_dimension_y = _max_texture_dimension;
- max_dimension_z = _max_2d_texture_array_layers;
- break;
- case Texture::TT_buffer_texture:
- max_dimension_x = _max_buffer_texture_size;
- max_dimension_y = 1;
- max_dimension_z = 1;
- break;
- default:
- max_dimension_x = _max_texture_dimension;
- max_dimension_y = _max_texture_dimension;
- max_dimension_z = 1;
- }
- if (max_dimension_x == 0 || max_dimension_y == 0 || max_dimension_z == 0) {
- // Guess this GL doesn't support cube mapping/3d textures/2d texture arrays.
- report_my_gl_errors();
- return false;
- }
- // If it doesn't fit, we have to reduce it on-the-fly. We do this
- // by incrementing the mipmap_bias, so we're effectively loading a
- // lower mipmap level. This requires generating the mipmaps on
- // the CPU if they haven't already been generated. It would have
- // been better if the user had specified max-texture-dimension to
- // reduce the texture at load time instead; of course, the user
- // doesn't always know ahead of time what the hardware limits are.
- if ((max_dimension_x > 0 && max_dimension_y > 0 && max_dimension_z > 0) &&
- image_compression == Texture::CM_off) {
- while (tex->get_expected_mipmap_x_size(mipmap_bias) > max_dimension_x ||
- tex->get_expected_mipmap_y_size(mipmap_bias) > max_dimension_y ||
- tex->get_expected_mipmap_z_size(mipmap_bias) > max_dimension_z) {
- ++mipmap_bias;
- }
- if (mipmap_bias >= tex->get_num_ram_mipmap_images()) {
- // We need to generate some more mipmap images.
- if (tex->has_ram_image()) {
- tex->generate_ram_mipmap_images();
- if (mipmap_bias >= tex->get_num_ram_mipmap_images()) {
- // It didn't work. Send the smallest we've got, and hope
- // for the best.
- mipmap_bias = tex->get_num_ram_mipmap_images() - 1;
- }
- }
- }
- width = tex->get_expected_mipmap_x_size(mipmap_bias);
- height = tex->get_expected_mipmap_y_size(mipmap_bias);
- depth = tex->get_expected_mipmap_z_size(mipmap_bias);
- if (mipmap_bias != 0) {
- GLCAT.info()
- << "Reducing image " << tex->get_name()
- << " from " << tex->get_x_size() << " x " << tex->get_y_size()
- << " x " << tex->get_z_size() << " to "
- << width << " x " << height << " x " << depth << "\n";
- }
- }
- if (image_compression != Texture::CM_off) {
- Texture::QualityLevel quality_level = tex->get_effective_quality_level();
- #ifndef OPENGLES
- switch (quality_level) {
- case Texture::QL_fastest:
- glHint(GL_TEXTURE_COMPRESSION_HINT, GL_FASTEST);
- break;
- case Texture::QL_default:
- case Texture::QL_normal:
- glHint(GL_TEXTURE_COMPRESSION_HINT, GL_DONT_CARE);
- break;
- case Texture::QL_best:
- glHint(GL_TEXTURE_COMPRESSION_HINT, GL_NICEST);
- break;
- }
- #endif
- }
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- GLenum target = get_texture_target(tex->get_texture_type());
- uses_mipmaps = (uses_mipmaps && !gl_ignore_mipmaps) || gl_force_mipmaps;
- #ifndef OPENGLES
- if (target == GL_TEXTURE_BUFFER) {
- // Buffer textures may not have mipmaps.
- uses_mipmaps = false;
- }
- #endif // OPENGLES
- bool needs_reload = false;
- if (!gtc->_has_storage ||
- gtc->_uses_mipmaps != uses_mipmaps ||
- gtc->_internal_format != internal_format ||
- gtc->_width != width ||
- gtc->_height != height ||
- gtc->_depth != depth) {
- // We need to reload a new GL Texture object.
- needs_reload = true;
- if (_use_object_labels) {
- // This seems like a good time to assign a label for the debug messages.
- const string &name = tex->get_name();
- _glObjectLabel(GL_TEXTURE, gtc->_index, name.size(), name.data());
- }
- }
- if (needs_reload && gtc->_immutable) {
- GLCAT.warning() << "Attempt to modify texture with immutable storage, recreating texture.\n";
- gtc->reset_data();
- glBindTexture(target, gtc->_index);
- }
- #ifndef OPENGLES
- if (target == GL_TEXTURE_BUFFER) {
- // Buffer textures don't support mipmappping.
- gtc->_generate_mipmaps = false;
- if (gtc->_buffer == 0) {
- // The buffer object wasn't created yet.
- _glGenBuffers(1, >c->_buffer);
- _glBindBuffer(GL_TEXTURE_BUFFER, gtc->_buffer);
- _glTexBuffer(GL_TEXTURE_BUFFER, internal_format, gtc->_buffer);
- needs_reload = true;
- } else {
- _glBindBuffer(GL_TEXTURE_BUFFER, gtc->_buffer);
- if (gtc->_internal_format != internal_format) {
- _glTexBuffer(GL_TEXTURE_BUFFER, internal_format, gtc->_buffer);
- }
- }
- } else
- #endif // !OPENGLES
- if (needs_reload) {
- // Figure out whether mipmaps will be generated by the GPU or by
- // Panda (or not at all), and how many mipmap levels should be created.
- gtc->_generate_mipmaps = false;
- int num_levels = 1;
- CPTA_uchar image = tex->get_ram_mipmap_image(mipmap_bias);
- if (image.is_null()) {
- // We don't even have a RAM image, so we have no choice but to let
- // mipmaps be generated on the GPU.
- if (uses_mipmaps) {
- if (_supports_generate_mipmap) {
- num_levels = tex->get_expected_num_mipmap_levels() - mipmap_bias;
- gtc->_generate_mipmaps = true;
- } else {
- // If it can't, do without mipmaps.
- num_levels = 1;
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- }
- }
- } else {
- if (uses_mipmaps) {
- num_levels = tex->get_num_ram_mipmap_images() - mipmap_bias;
- if (num_levels <= 1) {
- // No RAM mipmap levels available. Should we generate some?
- if (!_supports_generate_mipmap || !driver_generate_mipmaps ||
- image_compression != Texture::CM_off) {
- // Yes, the GL can't or won't generate them, so we need to.
- // Note that some drivers (nVidia) will *corrupt memory* if
- // you ask them to generate mipmaps for a pre-compressed
- // texture.
- tex->generate_ram_mipmap_images();
- num_levels = tex->get_num_ram_mipmap_images() - mipmap_bias;
- }
- }
- if (num_levels <= 1) {
- // We don't have mipmap levels in RAM. Ask the GL to generate
- // them if it can.
- if (_supports_generate_mipmap) {
- num_levels = tex->get_expected_num_mipmap_levels() - mipmap_bias;
- gtc->_generate_mipmaps = true;
- } else {
- // If it can't, do without mipmaps.
- glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- num_levels = 1;
- }
- }
- }
- }
- #ifndef OPENGLES // OpenGL ES doesn't have GL_TEXTURE_MAX_LEVEL.
- if (is_at_least_gl_version(1, 2)) {
- // By the time we get here, we have a pretty good prediction for
- // the number of mipmaps we're going to have, so tell the GL that's
- // all it's going to get.
- glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, num_levels - 1);
- }
- #endif
- #ifndef OPENGLES_2
- if (gtc->_generate_mipmaps && _glGenerateMipmap == NULL) {
- // The old, deprecated way to generate mipmaps.
- glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
- }
- #endif
- #if !defined(SUPPORT_FIXED_FUNCTION) && !defined(OPENGLES_2)
- // Do we need to apply a swizzle mask to emulate these deprecated
- // texture formats?
- switch (tex->get_format()) {
- case Texture::F_alpha:
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_ONE);
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_ONE);
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_ONE);
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_RED);
- break;
- case Texture::F_luminance:
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_RED);
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_RED);
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_ONE);
- break;
- case Texture::F_luminance_alpha:
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_R, GL_RED);
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_G, GL_RED);
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_B, GL_RED);
- glTexParameteri(target, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
- break;
- default:
- break;
- }
- #endif
- // Allocate immutable storage for the texture, after which we can subload it.
- // Pre-allocating storage using glTexStorage is more efficient than using glTexImage
- // to load all of the individual images one by one later, but we are not allowed to
- // change the texture size or number of mipmap levels after this point.
- if (gl_immutable_texture_storage && _supports_tex_storage && !gtc->_has_storage) {
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "allocating storage for texture " << tex->get_name() << ", " << width
- << " x " << height << " x " << depth << ", mipmaps " << num_levels
- << ", uses_mipmaps = " << uses_mipmaps << "\n";
- }
- switch (tex->get_texture_type()) {
- case Texture::TT_buffer_texture:
- // Won't get here, but squelch compiler warning
- case Texture::TT_1d_texture:
- _glTexStorage1D(target, num_levels, internal_format, width);
- break;
- case Texture::TT_2d_texture:
- case Texture::TT_cube_map:
- _glTexStorage2D(target, num_levels, internal_format, width, height);
- break;
- case Texture::TT_3d_texture:
- case Texture::TT_2d_texture_array:
- _glTexStorage3D(target, num_levels, internal_format, width, height, depth);
- break;
- }
- gtc->_has_storage = true;
- gtc->_immutable = true;
- gtc->_uses_mipmaps = uses_mipmaps;
- gtc->_internal_format = internal_format;
- gtc->_width = width;
- gtc->_height = height;
- gtc->_depth = depth;
- needs_reload = false;
- }
- } else {
- // Maybe we need to generate mipmaps on the CPU.
- if (!image.is_null() && uses_mipmaps) {
- if (tex->get_num_ram_mipmap_images() - mipmap_bias <= 1) {
- // No RAM mipmap levels available. Should we generate some?
- if (!_supports_generate_mipmap || !driver_generate_mipmaps ||
- image_compression != Texture::CM_off) {
- // Yes, the GL can't or won't generate them, so we need to.
- // Note that some drivers (nVidia) will *corrupt memory* if
- // you ask them to generate mipmaps for a pre-compressed
- // texture.
- tex->generate_ram_mipmap_images();
- }
- }
- }
- }
- bool success = true;
- if (tex->get_texture_type() == Texture::TT_cube_map) {
- // A cube map must load six different 2-d images (which are stored
- // as the six pages of the system ram image).
- if (!_supports_cube_map) {
- report_my_gl_errors();
- return false;
- }
- nassertr(target == GL_TEXTURE_CUBE_MAP, false);
- success = success && upload_texture_image
- (gtc, needs_reload, uses_mipmaps, mipmap_bias,
- GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
- internal_format, external_format, component_type,
- true, 0, image_compression);
- success = success && upload_texture_image
- (gtc, needs_reload, uses_mipmaps, mipmap_bias,
- GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
- internal_format, external_format, component_type,
- true, 1, image_compression);
- success = success && upload_texture_image
- (gtc, needs_reload, uses_mipmaps, mipmap_bias,
- GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
- internal_format, external_format, component_type,
- true, 2, image_compression);
- success = success && upload_texture_image
- (gtc, needs_reload, uses_mipmaps, mipmap_bias,
- GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
- internal_format, external_format, component_type,
- true, 3, image_compression);
- success = success && upload_texture_image
- (gtc, needs_reload, uses_mipmaps, mipmap_bias,
- GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
- internal_format, external_format, component_type,
- true, 4, image_compression);
- success = success && upload_texture_image
- (gtc, needs_reload, uses_mipmaps, mipmap_bias,
- GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
- internal_format, external_format, component_type,
- true, 5, image_compression);
- } else {
- // Any other kind of texture can be loaded all at once.
- success = upload_texture_image
- (gtc, needs_reload, uses_mipmaps, mipmap_bias, target,
- target, internal_format, external_format,
- component_type, false, 0, image_compression);
- }
- if (gtc->_generate_mipmaps && _glGenerateMipmap != NULL &&
- !image.is_null()) {
- // We uploaded an image; we may need to generate mipmaps.
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "generating mipmaps for texture " << tex->get_name() << ", "
- << width << " x " << height << " x " << depth
- << ", uses_mipmaps = " << uses_mipmaps << "\n";
- }
- _glGenerateMipmap(target);
- }
- maybe_gl_finish();
- if (success) {
- if (needs_reload) {
- gtc->_has_storage = true;
- gtc->_uses_mipmaps = uses_mipmaps;
- gtc->_internal_format = internal_format;
- gtc->_width = width;
- gtc->_height = height;
- gtc->_depth = depth;
- gtc->update_data_size_bytes(get_texture_memory_size(tex));
- }
- if (tex->get_post_load_store_cache()) {
- tex->set_post_load_store_cache(false);
- // OK, get the RAM image, and save it in a BamCache record.
- if (do_extract_texture_data(gtc)) {
- if (tex->has_ram_image()) {
- BamCache *cache = BamCache::get_global_ptr();
- PT(BamCacheRecord) record = cache->lookup(tex->get_fullpath(), "txo");
- if (record != (BamCacheRecord *)NULL) {
- record->set_data(tex, tex);
- cache->store(record);
- }
- }
- }
- }
- GraphicsEngine *engine = get_engine();
- nassertr(engine != (GraphicsEngine *)NULL, false);
- engine->texture_uploaded(tex);
- gtc->mark_loaded();
- report_my_gl_errors();
- return true;
- }
- report_my_gl_errors();
- return false;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::upload_texture_image
- // Access: Protected
- // Description: Loads a texture image, or one page of a cube map
- // image, from system RAM to texture memory.
- //
- // texture_target is normally the same thing as
- // page_target; both represent the GL target onto which
- // the texture image is loaded, e.g. GL_TEXTURE_1D,
- // GL_TEXTURE_2D, etc. The only time they may differ is
- // in the case of cube mapping, in which case
- // texture_target will be target for the overall
- // texture, e.g. GL_TEXTURE_CUBE_MAP, and page_target
- // will be the target for this particular page,
- // e.g. GL_TEXTURE_CUBE_MAP_POSITIVE_X.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
- bool uses_mipmaps, int mipmap_bias,
- GLenum texture_target, GLenum page_target,
- GLint internal_format,
- GLint external_format, GLenum component_type,
- bool one_page_only, int z,
- Texture::CompressionMode image_compression) {
- // Make sure the error stack is cleared out before we begin.
- clear_my_gl_errors();
- if (texture_target == GL_NONE) {
- // Unsupported target (e.g. 3-d texturing on GL 1.1).
- return false;
- }
- if (image_compression != Texture::CM_off && !_supports_compressed_texture) {
- return false;
- }
- Texture *tex = gtc->get_texture();
- nassertr(tex != (Texture *)NULL, false);
- CPTA_uchar image = tex->get_ram_mipmap_image(mipmap_bias);
- int width = tex->get_expected_mipmap_x_size(mipmap_bias);
- int height = tex->get_expected_mipmap_y_size(mipmap_bias);
- int depth = tex->get_expected_mipmap_z_size(mipmap_bias);
- // Determine the number of images to upload.
- int num_levels = 1;
- if (uses_mipmaps) {
- num_levels = tex->get_expected_num_mipmap_levels();
- }
- int num_ram_mipmap_levels = 0;
- if (!image.is_null()) {
- if (uses_mipmaps) {
- num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
- } else {
- num_ram_mipmap_levels = 1;
- }
- }
- #ifndef OPENGLES
- if (needs_reload || num_ram_mipmap_levels > 0) {
- // Make sure that any incoherent writes to this texture have been synced.
- if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT)) {
- issue_memory_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
- }
- }
- #endif
- if (!needs_reload) {
- // Try to subload the image over the existing GL Texture object,
- // possibly saving on texture memory fragmentation.
- if (GLCAT.is_debug()) {
- if (num_ram_mipmap_levels == 0) {
- if (tex->has_clear_color()) {
- GLCAT.debug()
- << "clearing texture " << tex->get_name() << ", "
- << width << " x " << height << " x " << depth << ", z = " << z
- << ", uses_mipmaps = " << uses_mipmaps << ", clear_color = "
- << tex->get_clear_color() << "\n";
- } else {
- GLCAT.debug()
- << "not loading NULL image for texture " << tex->get_name()
- << ", " << width << " x " << height << " x " << depth
- << ", z = " << z << ", uses_mipmaps = " << uses_mipmaps << "\n";
- }
- } else {
- GLCAT.debug()
- << "updating image data of texture " << tex->get_name()
- << ", " << width << " x " << height << " x " << depth
- << ", z = " << z << ", mipmaps " << num_ram_mipmap_levels
- << ", uses_mipmaps = " << uses_mipmaps << "\n";
- }
- }
- for (int n = mipmap_bias; n < num_levels; ++n) {
- // we grab the mipmap pointer first, if it is NULL we grab the
- // normal mipmap image pointer which is a PTA_uchar
- const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n);
- CPTA_uchar ptimage;
- if (image_ptr == (const unsigned char *)NULL) {
- ptimage = tex->get_ram_mipmap_image(n);
- if (ptimage.is_null()) {
- if (n < num_ram_mipmap_levels) {
- // We were told we'd have this many RAM mipmap images, but
- // we don't. Raise a warning.
- GLCAT.warning()
- << "No mipmap level " << n << " defined for " << tex->get_name()
- << "\n";
- break;
- }
- if (tex->has_clear_color()) {
- // The texture has a clear color, so we should fill this mipmap
- // level to a solid color.
- #ifndef OPENGLES
- if (_supports_clear_texture) {
- // We can do that with the convenient glClearTexImage function.
- string clear_data = tex->get_clear_data();
- _glClearTexImage(gtc->_index, n - mipmap_bias, external_format,
- component_type, (void *)clear_data.data());
- continue;
- }
- #endif // OPENGLES
- // Ask the Texture class to create the mipmap level in RAM.
- // It'll fill it in with the correct clear color, which we
- // can then upload.
- ptimage = tex->make_ram_mipmap_image(n);
- } else {
- // No clear color and no more images.
- break;
- }
- }
- image_ptr = ptimage;
- }
- PTA_uchar bgr_image;
- size_t view_size = tex->get_ram_mipmap_view_size(n);
- if (image_ptr != (const unsigned char *)NULL) {
- const unsigned char *orig_image_ptr = image_ptr;
- image_ptr += view_size * gtc->get_view();
- if (one_page_only) {
- view_size = tex->get_ram_mipmap_page_size(n);
- image_ptr += view_size * z;
- }
- nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false);
- if (!_supports_bgr && image_compression == Texture::CM_off) {
- // If the GL doesn't claim to support BGR, we may have to reverse
- // the component ordering of the image.
- image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size,
- external_format, tex);
- }
- }
- int width = tex->get_expected_mipmap_x_size(n);
- int height = tex->get_expected_mipmap_y_size(n);
- int depth = tex->get_expected_mipmap_z_size(n);
- #ifdef DO_PSTATS
- _data_transferred_pcollector.add_level(view_size);
- #endif
- switch (texture_target) {
- #ifndef OPENGLES_1
- case GL_TEXTURE_3D:
- if (_supports_3d_texture) {
- if (image_compression == Texture::CM_off) {
- _glTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
- external_format, component_type, image_ptr);
- } else {
- _glCompressedTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
- external_format, view_size, image_ptr);
- }
- } else {
- report_my_gl_errors();
- return false;
- }
- break;
- #endif // OPENGLES_1
- #ifndef OPENGLES
- case GL_TEXTURE_1D:
- if (image_compression == Texture::CM_off) {
- glTexSubImage1D(page_target, n - mipmap_bias, 0, width,
- external_format, component_type, image_ptr);
- } else {
- _glCompressedTexSubImage1D(page_target, n - mipmap_bias, 0, width,
- external_format, view_size, image_ptr);
- }
- break;
- #endif // OPENGLES
- #ifndef OPENGLES
- case GL_TEXTURE_2D_ARRAY_EXT:
- if (_supports_2d_texture_array) {
- if (image_compression == Texture::CM_off) {
- _glTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
- external_format, component_type, image_ptr);
- } else {
- _glCompressedTexSubImage3D(page_target, n - mipmap_bias, 0, 0, 0, width, height, depth,
- external_format, view_size, image_ptr);
- }
- } else {
- report_my_gl_errors();
- return false;
- }
- break;
- #endif // OPENGLES
- #ifndef OPENGLES
- case GL_TEXTURE_BUFFER:
- if (_supports_buffer_texture) {
- _glBufferSubData(GL_TEXTURE_BUFFER, 0, view_size, image_ptr);
- } else {
- report_my_gl_errors();
- return false;
- }
- break;
- #endif // OPENGLES
- default:
- if (image_compression == Texture::CM_off) {
- if (n==0) {
- // It's unfortunate that we can't adjust the width, too,
- // but TexSubImage2D doesn't accept a row-stride parameter.
- height = tex->get_y_size() - tex->get_pad_y_size();
- }
- glTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height,
- external_format, component_type, image_ptr);
- } else {
- _glCompressedTexSubImage2D(page_target, n - mipmap_bias, 0, 0, width, height,
- external_format, view_size, image_ptr);
- }
- break;
- }
- }
- // Did that fail? If it did, we'll immediately try again, this
- // time loading the texture from scratch.
- GLenum error_code = gl_get_error();
- if (error_code != GL_NO_ERROR) {
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "GL texture subload failed for " << tex->get_name()
- << " : " << get_error_string(error_code) << "\n";
- }
- needs_reload = true;
- }
- }
- if (needs_reload) {
- // Load the image up from scratch, creating a new GL Texture
- // object.
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "loading new texture object for " << tex->get_name() << ", " << width
- << " x " << height << " x " << depth << ", z = " << z << ", mipmaps "
- << num_ram_mipmap_levels << ", uses_mipmaps = " << uses_mipmaps << "\n";
- }
- // If there is immutable storage, this is impossible to do, and we should
- // not have gotten here at all.
- nassertr(!gtc->_immutable, false);
- if (num_ram_mipmap_levels == 0) {
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << " (initializing NULL image)\n";
- }
- if ((external_format == GL_DEPTH_STENCIL) && get_supports_depth_stencil()) {
- #ifdef OPENGLES
- component_type = GL_UNSIGNED_INT_24_8_OES;
- #else
- component_type = GL_UNSIGNED_INT_24_8_EXT;
- #endif
- }
- }
- for (int n = mipmap_bias; n < num_levels; ++n) {
- const unsigned char *image_ptr = (unsigned char*)tex->get_ram_mipmap_pointer(n);
- CPTA_uchar ptimage;
- if (image_ptr == (const unsigned char *)NULL) {
- ptimage = tex->get_ram_mipmap_image(n);
- if (ptimage.is_null()) {
- if (n < num_ram_mipmap_levels) {
- // We were told we'd have this many RAM mipmap images, but
- // we don't. Raise a warning.
- GLCAT.warning()
- << "No mipmap level " << n << " defined for " << tex->get_name()
- << "\n";
- #ifndef OPENGLES
- if (is_at_least_gl_version(1, 2)) {
- // Tell the GL we have no more mipmaps for it to use.
- glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias);
- }
- #endif
- break;
- }
- if (tex->has_clear_color()) {
- // Ask the Texture class to create the mipmap level in RAM.
- // It'll fill it in with the correct clear color, which we
- // can then upload.
- ptimage = tex->make_ram_mipmap_image(n);
- }
- }
- image_ptr = ptimage;
- }
- PTA_uchar bgr_image;
- size_t view_size = tex->get_ram_mipmap_view_size(n);
- if (image_ptr != (const unsigned char *)NULL) {
- const unsigned char *orig_image_ptr = image_ptr;
- image_ptr += view_size * gtc->get_view();
- if (one_page_only) {
- view_size = tex->get_ram_mipmap_page_size(n);
- image_ptr += view_size * z;
- }
- nassertr(image_ptr >= orig_image_ptr && image_ptr + view_size <= orig_image_ptr + tex->get_ram_mipmap_image_size(n), false);
- if (!_supports_bgr && image_compression == Texture::CM_off) {
- // If the GL doesn't claim to support BGR, we may have to reverse
- // the component ordering of the image.
- image_ptr = fix_component_ordering(bgr_image, image_ptr, view_size,
- external_format, tex);
- }
- }
- int width = tex->get_expected_mipmap_x_size(n);
- int height = tex->get_expected_mipmap_y_size(n);
- int depth = tex->get_expected_mipmap_z_size(n);
- #ifdef DO_PSTATS
- _data_transferred_pcollector.add_level(view_size);
- #endif
- switch (texture_target) {
- #ifndef OPENGLES // 1-d textures not supported by OpenGL ES. Fall through.
- case GL_TEXTURE_1D:
- if (image_compression == Texture::CM_off) {
- glTexImage1D(page_target, n - mipmap_bias, internal_format,
- width, 0,
- external_format, component_type, image_ptr);
- } else {
- _glCompressedTexImage1D(page_target, n - mipmap_bias, external_format, width,
- 0, view_size, image_ptr);
- }
- break;
- #endif // OPENGLES // OpenGL ES will fall through.
- #ifdef OPENGLES_2
- case GL_TEXTURE_3D_OES:
- #endif
- #ifndef OPENGLES
- case GL_TEXTURE_3D:
- #endif
- #ifndef OPENGLES_1
- if (_supports_3d_texture) {
- if (image_compression == Texture::CM_off) {
- _glTexImage3D(page_target, n - mipmap_bias, internal_format,
- width, height, depth, 0,
- external_format, component_type, image_ptr);
- } else {
- _glCompressedTexImage3D(page_target, n - mipmap_bias, external_format, width,
- height, depth,
- 0, view_size, image_ptr);
- }
- } else {
- report_my_gl_errors();
- return false;
- }
- break;
- #endif
- #ifndef OPENGLES
- case GL_TEXTURE_2D_ARRAY_EXT:
- if (_supports_2d_texture_array) {
- if (image_compression == Texture::CM_off) {
- _glTexImage3D(page_target, n - mipmap_bias, internal_format,
- width, height, depth, 0,
- external_format, component_type, image_ptr);
- } else {
- _glCompressedTexImage3D(page_target, n - mipmap_bias, external_format, width,
- height, depth,
- 0, view_size, image_ptr);
- }
- } else {
- report_my_gl_errors();
- return false;
- }
- break;
- #endif // OPENGLES
- #ifndef OPENGLES
- case GL_TEXTURE_BUFFER:
- if (_supports_buffer_texture) {
- _glBufferData(GL_TEXTURE_BUFFER, view_size, image_ptr,
- get_usage(tex->get_usage_hint()));
- } else {
- report_my_gl_errors();
- return false;
- }
- break;
- #endif // OPENGLES
- default:
- if (image_compression == Texture::CM_off) {
- glTexImage2D(page_target, n - mipmap_bias, internal_format,
- width, height, 0,
- external_format, component_type, image_ptr);
- } else {
- _glCompressedTexImage2D(page_target, n - mipmap_bias, external_format,
- width, height, 0, view_size, image_ptr);
- }
- }
- }
- // Report the error message explicitly if the GL texture creation
- // failed.
- GLenum error_code = gl_get_error();
- if (error_code != GL_NO_ERROR) {
- GLCAT.error()
- << "GL texture creation failed for " << tex->get_name()
- << " : " << get_error_string(error_code) << "\n";
- gtc->_has_storage = false;
- return false;
- }
- }
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::upload_simple_texture
- // Access: Protected
- // Description: This is used as a standin for upload_texture
- // when the texture in question is unavailable (e.g. it
- // hasn't yet been loaded from disk). Until the texture
- // image itself becomes available, we will render the
- // texture's "simple" image--a sharply reduced version
- // of the same texture.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- upload_simple_texture(CLP(TextureContext) *gtc) {
- report_my_gl_errors();
- PStatGPUTimer timer(this, _load_texture_pcollector);
- Texture *tex = gtc->get_texture();
- nassertr(tex != (Texture *)NULL, false);
- int internal_format = GL_RGBA;
- #ifdef OPENGLES_2
- int external_format = GL_RGBA;
- #else
- int external_format = GL_BGRA;
- #endif
- const unsigned char *image_ptr = tex->get_simple_ram_image();
- if (image_ptr == (const unsigned char *)NULL) {
- return false;
- }
- size_t image_size = tex->get_simple_ram_image_size();
- PTA_uchar bgr_image;
- if (!_supports_bgr) {
- // If the GL doesn't claim to support BGR, we may have to reverse
- // the component ordering of the image.
- external_format = GL_RGBA;
- image_ptr = fix_component_ordering(bgr_image, image_ptr, image_size,
- external_format, tex);
- }
- int width = tex->get_simple_x_size();
- int height = tex->get_simple_y_size();
- int component_type = GL_UNSIGNED_BYTE;
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "loading simple image for " << tex->get_name() << "\n";
- }
- #ifndef OPENGLES
- // Turn off mipmaps for the simple texture.
- if (tex->uses_mipmaps()) {
- if (is_at_least_gl_version(1, 2)) {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
- }
- }
- #endif
- #ifdef DO_PSTATS
- _data_transferred_pcollector.add_level(image_size);
- #endif
- glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
- width, height, 0,
- external_format, component_type, image_ptr);
- gtc->mark_simple_loaded();
- report_my_gl_errors();
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_texture_memory_size
- // Access: Protected
- // Description: Asks OpenGL how much texture memory is consumed by
- // the indicated texture (which is also the
- // currently-selected texture).
- ////////////////////////////////////////////////////////////////////
- size_t CLP(GraphicsStateGuardian)::
- get_texture_memory_size(Texture *tex) {
- #ifdef OPENGLES // Texture querying not supported on OpenGL ES.
- int width = tex->get_x_size();
- int height = tex->get_y_size();
- int depth = 1;
- int scale = 1;
- bool has_mipmaps = tex->uses_mipmaps();
- size_t num_bytes = 2; // Temporary assumption?
- #else
- GLenum target = get_texture_target(tex->get_texture_type());
- GLenum page_target = target;
- GLint scale = 1;
- if (target == GL_TEXTURE_CUBE_MAP) {
- // We need a particular page to get the level parameter from.
- page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
- scale = 6;
- } else if (target == GL_TEXTURE_BUFFER) {
- // In the case of buffer textures, we provided the size to begin with,
- // so no point in querying anything. Plus, glGetTexParameter is not even
- // supported for buffer textures.
- return tex->get_expected_ram_image_size();
- }
- GLint minfilter;
- glGetTexParameteriv(target, GL_TEXTURE_MIN_FILTER, &minfilter);
- bool has_mipmaps = is_mipmap_filter(minfilter);
- clear_my_gl_errors();
- GLint internal_format;
- glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
- if (is_compressed_format(internal_format)) {
- // Try to get the compressed size.
- GLint image_size;
- glGetTexLevelParameteriv(page_target, 0,
- GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
- GLenum error_code = gl_get_error();
- if (error_code != GL_NO_ERROR) {
- if (GLCAT.is_debug()) {
- GLCAT.debug()
- << "Couldn't get compressed size for " << tex->get_name()
- << " : " << get_error_string(error_code) << "\n";
- }
- // Fall through to the noncompressed case.
- } else {
- return image_size * scale;
- }
- }
- // OK, get the noncompressed size.
- GLint red_size, green_size, blue_size, alpha_size,
- luminance_size, intensity_size;
- GLint depth_size = 0;
- glGetTexLevelParameteriv(page_target, 0,
- GL_TEXTURE_RED_SIZE, &red_size);
- glGetTexLevelParameteriv(page_target, 0,
- GL_TEXTURE_GREEN_SIZE, &green_size);
- glGetTexLevelParameteriv(page_target, 0,
- GL_TEXTURE_BLUE_SIZE, &blue_size);
- glGetTexLevelParameteriv(page_target, 0,
- GL_TEXTURE_ALPHA_SIZE, &alpha_size);
- glGetTexLevelParameteriv(page_target, 0,
- GL_TEXTURE_LUMINANCE_SIZE, &luminance_size);
- glGetTexLevelParameteriv(page_target, 0,
- GL_TEXTURE_INTENSITY_SIZE, &intensity_size);
- if (_supports_depth_texture) {
- glGetTexLevelParameteriv(page_target, 0,
- GL_TEXTURE_DEPTH_SIZE, &depth_size);
- }
- GLint width = 1, height = 1, depth = 1;
- glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_WIDTH, &width);
- glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_HEIGHT, &height);
- if (_supports_3d_texture || _supports_2d_texture_array) {
- glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_DEPTH, &depth);
- }
- report_my_gl_errors();
- size_t num_bits = (red_size + green_size + blue_size + alpha_size + luminance_size + intensity_size + depth_size);
- size_t num_bytes = (num_bits + 7) / 8;
- #endif // OPENGLES
- size_t result = num_bytes * width * height * depth * scale;
- if (has_mipmaps) {
- result = (result * 4) / 3;
- }
- return result;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::check_nonresident_texture
- // Access: Private
- // Description: Checks the list of resident texture objects to see if
- // any have recently been evicted.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- check_nonresident_texture(BufferContextChain &chain) {
- #ifndef OPENGLES // Residency queries not supported by OpenGL ES.
- size_t num_textures = chain.get_count();
- if (num_textures == 0) {
- return;
- }
- CLP(TextureContext) **gtc_list = (CLP(TextureContext) **)alloca(num_textures * sizeof(CLP(TextureContext) *));
- GLuint *texture_list = (GLuint *)alloca(num_textures * sizeof(GLuint));
- size_t ti = 0;
- BufferContext *node = chain.get_first();
- while (node != (BufferContext *)NULL) {
- CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), node);
- gtc_list[ti] = gtc;
- texture_list[ti] = gtc->_index;
- node = node->get_next();
- ++ti;
- }
- nassertv(ti == num_textures);
- GLboolean *results = (GLboolean *)alloca(num_textures * sizeof(GLboolean));
- bool all_resident = (glAreTexturesResident(num_textures, texture_list, results) != 0);
- report_my_gl_errors();
- if (!all_resident) {
- // Some are now nonresident.
- for (ti = 0; ti < num_textures; ++ti) {
- if (!results[ti]) {
- gtc_list[ti]->set_resident(false);
- }
- }
- }
- #endif // OPENGLES
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_extract_texture_data
- // Access: Protected
- // Description: The internal implementation of
- // extract_texture_data(), given an already-created
- // TextureContext.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- do_extract_texture_data(CLP(TextureContext) *gtc) {
- report_my_gl_errors();
- GLenum target = gtc->_target;
- if (target == GL_NONE) {
- return false;
- }
- #ifndef OPENGLES
- // Make sure any incoherent writes to the texture have been synced.
- if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT)) {
- issue_memory_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
- }
- #endif
- glBindTexture(target, gtc->_index);
- Texture *tex = gtc->get_texture();
- GLint wrap_u, wrap_v, wrap_w;
- GLint minfilter, magfilter;
- GLfloat border_color[4];
- glGetTexParameteriv(target, GL_TEXTURE_WRAP_S, &wrap_u);
- glGetTexParameteriv(target, GL_TEXTURE_WRAP_T, &wrap_v);
- wrap_w = GL_REPEAT;
- if (_supports_3d_texture) {
- #ifdef OPENGLES_2
- glGetTexParameteriv(target, GL_TEXTURE_WRAP_R_OES, &wrap_w);
- #endif
- #ifndef OPENGLES
- glGetTexParameteriv(target, GL_TEXTURE_WRAP_R, &wrap_w);
- #endif
- }
- if (_supports_2d_texture_array) {
- #ifndef OPENGLES
- glGetTexParameteriv(target, GL_TEXTURE_WRAP_R, &wrap_w);
- #endif
- }
- glGetTexParameteriv(target, GL_TEXTURE_MIN_FILTER, &minfilter);
- glGetTexParameteriv(target, GL_TEXTURE_MAG_FILTER, &magfilter);
- #ifndef OPENGLES
- glGetTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, border_color);
- #endif
- GLenum page_target = target;
- if (target == GL_TEXTURE_CUBE_MAP) {
- // We need a particular page to get the level parameter from.
- page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
- }
- GLint width = gtc->_width, height = gtc->_height, depth = gtc->_depth;
- #ifndef OPENGLES
- glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_WIDTH, &width);
- if (target != GL_TEXTURE_1D) {
- glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_HEIGHT, &height);
- }
- if (_supports_3d_texture && target == GL_TEXTURE_3D) {
- glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_DEPTH, &depth);
- }
- #ifndef OPENGLES
- else if (_supports_2d_texture_array && target == GL_TEXTURE_2D_ARRAY_EXT) {
- glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_DEPTH, &depth);
- }
- #endif
- else if (target == GL_TEXTURE_CUBE_MAP) {
- depth = 6;
- }
- #endif
- clear_my_gl_errors();
- if (width <= 0 || height <= 0 || depth <= 0) {
- GLCAT.error()
- << "No texture data for " << tex->get_name() << "\n";
- return false;
- }
- GLint internal_format = GL_RGBA;
- #ifndef OPENGLES
- glGetTexLevelParameteriv(page_target, 0, GL_TEXTURE_INTERNAL_FORMAT, &internal_format);
- #endif // OPENGLES
- // Make sure we were able to query those parameters properly.
- GLenum error_code = gl_get_error();
- if (error_code != GL_NO_ERROR) {
- GLCAT.error()
- << "Unable to query texture parameters for " << tex->get_name()
- << " : " << get_error_string(error_code) << "\n";
- return false;
- }
- Texture::ComponentType type = Texture::T_unsigned_byte;
- Texture::Format format = Texture::F_rgb;
- Texture::CompressionMode compression = Texture::CM_off;
- switch (internal_format) {
- #ifndef OPENGLES
- case GL_COLOR_INDEX:
- format = Texture::F_color_index;
- break;
- #endif
- #if GL_DEPTH_COMPONENT != GL_DEPTH_COMPONENT24
- case GL_DEPTH_COMPONENT:
- #endif
- case GL_DEPTH_COMPONENT16:
- case GL_DEPTH_COMPONENT24:
- case GL_DEPTH_COMPONENT32:
- type = Texture::T_unsigned_short;
- format = Texture::F_depth_component;
- break;
- #ifndef OPENGLES
- case GL_DEPTH_COMPONENT32F:
- type = Texture::T_float;
- format = Texture::F_depth_component;
- break;
- #endif
- case GL_DEPTH_STENCIL:
- case GL_DEPTH24_STENCIL8:
- type = Texture::T_unsigned_int_24_8;
- format = Texture::F_depth_stencil;
- break;
- #ifndef OPENGLES
- case GL_DEPTH32F_STENCIL8:
- type = Texture::T_float;
- format = Texture::F_depth_stencil;
- break;
- #endif
- case GL_RGBA:
- case 4:
- format = Texture::F_rgba;
- break;
- case GL_RGBA4:
- format = Texture::F_rgba4;
- break;
- #ifdef OPENGLES
- case GL_RGBA8_OES:
- format = Texture::F_rgba8;
- break;
- #else
- case GL_RGBA8:
- format = Texture::F_rgba8;
- break;
- #endif
- #ifndef OPENGLES
- case GL_RGBA12:
- type = Texture::T_unsigned_short;
- format = Texture::F_rgba12;
- break;
- #endif
- case GL_RGB:
- case 3:
- format = Texture::F_rgb;
- break;
- #ifndef OPENGLES
- case GL_RGB5:
- format = Texture::F_rgb5;
- break;
- #endif
- case GL_RGB5_A1:
- format = Texture::F_rgba5;
- break;
- #ifndef OPENGLES
- case GL_RGB8:
- format = Texture::F_rgb8;
- break;
- case GL_RGB12:
- format = Texture::F_rgb12;
- break;
- case GL_RGBA16:
- format = Texture::F_rgba16;
- break;
- case GL_R3_G3_B2:
- format = Texture::F_rgb332;
- break;
- case GL_R8I:
- format = Texture::F_r8i;
- break;
- case GL_RG8I:
- format = Texture::F_rg8i;
- break;
- case GL_RGB8I:
- format = Texture::F_rgb8i;
- break;
- case GL_RGBA8I:
- format = Texture::F_rgba8i;
- break;
- case GL_R8UI:
- type = Texture::T_unsigned_byte;
- format = Texture::F_r8i;
- break;
- case GL_RG8UI:
- type = Texture::T_unsigned_byte;
- format = Texture::F_rg8i;
- break;
- case GL_RGB8UI:
- type = Texture::T_unsigned_byte;
- format = Texture::F_rgb8i;
- break;
- case GL_RGBA8UI:
- type = Texture::T_unsigned_byte;
- format = Texture::F_rgba8i;
- break;
- #endif
- #ifndef OPENGLES_1
- case GL_RGBA16F:
- type = Texture::T_float;
- format = Texture::F_rgba16;
- break;
- case GL_RGB16F:
- type = Texture::T_float;
- format = Texture::F_rgb16;
- break;
- case GL_RG16F:
- type = Texture::T_float;
- format = Texture::F_rg16;
- break;
- case GL_R16F:
- type = Texture::T_float;
- format = Texture::F_r16;
- break;
- case GL_RGBA32F:
- type = Texture::T_float;
- format = Texture::F_rgba32;
- break;
- case GL_RGB32F:
- type = Texture::T_float;
- format = Texture::F_rgb32;
- break;
- case GL_RG32F:
- type = Texture::T_float;
- format = Texture::F_rg32;
- break;
- case GL_R32F:
- type = Texture::T_float;
- format = Texture::F_r32;
- break;
- #endif
- #ifndef OPENGLES
- case GL_RGB16:
- type = Texture::T_unsigned_short;
- format = Texture::F_rgb16;
- break;
- case GL_RG16:
- type = Texture::T_unsigned_short;
- format = Texture::F_rg16;
- break;
- case GL_R16:
- type = Texture::T_unsigned_short;
- format = Texture::F_r16;
- break;
- #endif
- #ifdef OPENGLES_2
- case GL_RED_EXT:
- case GL_R8_EXT:
- format = Texture::F_red;
- break;
- #endif
- #ifndef OPENGLES
- case GL_R32I:
- type = Texture::T_int;
- format = Texture::F_r32i;
- break;
- #endif
- #ifndef OPENGLES
- case GL_RED:
- format = Texture::F_red;
- break;
- case GL_GREEN:
- format = Texture::F_green;
- break;
- case GL_BLUE:
- format = Texture::F_blue;
- break;
- #endif // OPENGLES
- case GL_ALPHA:
- format = Texture::F_alpha;
- break;
- case GL_LUMINANCE:
- #ifndef OPENGLES
- case GL_LUMINANCE16:
- case GL_LUMINANCE16F_ARB:
- #endif
- case 1:
- format = Texture::F_luminance;
- break;
- case GL_LUMINANCE_ALPHA:
- #ifndef OPENGLES
- case GL_LUMINANCE_ALPHA16F_ARB:
- #endif
- case 2:
- format = Texture::F_luminance_alpha;
- break;
- #ifndef OPENGLES_1
- case GL_SRGB:
- #ifndef OPENGLES
- case GL_SRGB8:
- #endif
- format = Texture::F_srgb;
- break;
- case GL_SRGB_ALPHA:
- case GL_SRGB8_ALPHA8:
- format = Texture::F_srgb_alpha;
- break;
- #endif // OPENGLES_1
- #ifndef OPENGLES
- case GL_SLUMINANCE:
- case GL_SLUMINANCE8:
- format = Texture::F_sluminance;
- break;
- case GL_SLUMINANCE_ALPHA:
- case GL_SLUMINANCE8_ALPHA8:
- format = Texture::F_sluminance_alpha;
- break;
- #endif // OPENGLES
- #ifndef OPENGLES
- case GL_COMPRESSED_RGB:
- format = Texture::F_rgb;
- compression = Texture::CM_on;
- break;
- case GL_COMPRESSED_RGBA:
- format = Texture::F_rgba;
- compression = Texture::CM_on;
- break;
- case GL_COMPRESSED_ALPHA:
- format = Texture::F_alpha;
- compression = Texture::CM_on;
- break;
- case GL_COMPRESSED_LUMINANCE:
- format = Texture::F_luminance;
- compression = Texture::CM_on;
- break;
- case GL_COMPRESSED_LUMINANCE_ALPHA:
- format = Texture::F_luminance_alpha;
- compression = Texture::CM_on;
- break;
- case GL_COMPRESSED_SRGB:
- format = Texture::F_srgb;
- compression = Texture::CM_on;
- break;
- case GL_COMPRESSED_SRGB_ALPHA:
- format = Texture::F_srgb_alpha;
- compression = Texture::CM_on;
- break;
- case GL_COMPRESSED_SLUMINANCE:
- format = Texture::F_sluminance;
- compression = Texture::CM_on;
- break;
- case GL_COMPRESSED_SLUMINANCE_ALPHA:
- format = Texture::F_sluminance_alpha;
- compression = Texture::CM_on;
- break;
- #endif
- case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
- format = Texture::F_rgb;
- compression = Texture::CM_dxt1;
- break;
- case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
- format = Texture::F_rgbm;
- compression = Texture::CM_dxt1;
- break;
- #ifndef OPENGLES
- case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
- format = Texture::F_srgb;
- compression = Texture::CM_dxt1;
- break;
- case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
- format = Texture::F_srgb_alpha;
- compression = Texture::CM_dxt1;
- break;
- #endif
- #ifdef OPENGLES
- case GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
- format = Texture::F_rgb;
- compression = Texture::CM_pvr1_2bpp;
- break;
- case GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
- format = Texture::F_rgba;
- compression = Texture::CM_pvr1_2bpp;
- break;
- case GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
- format = Texture::F_rgb;
- compression = Texture::CM_pvr1_4bpp;
- break;
- case GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
- format = Texture::F_rgba;
- compression = Texture::CM_pvr1_4bpp;
- break;
- #else
- case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
- format = Texture::F_rgba;
- compression = Texture::CM_dxt3;
- break;
- case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
- format = Texture::F_rgba;
- compression = Texture::CM_dxt5;
- break;
- case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
- format = Texture::F_srgb_alpha;
- compression = Texture::CM_dxt3;
- break;
- case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
- format = Texture::F_srgb_alpha;
- compression = Texture::CM_dxt5;
- break;
- case GL_COMPRESSED_RGB_FXT1_3DFX:
- format = Texture::F_rgb;
- compression = Texture::CM_fxt1;
- break;
- case GL_COMPRESSED_RGBA_FXT1_3DFX:
- format = Texture::F_rgba;
- compression = Texture::CM_fxt1;
- break;
- #endif
- default:
- GLCAT.warning()
- << "Unhandled internal format for " << tex->get_name()
- << " : " << hex << "0x" << internal_format << dec << "\n";
- return false;
- }
- // We don't want to call setup_texture() again; that resets too
- // much. Instead, we'll just set the individual components.
- tex->set_x_size(width);
- tex->set_y_size(height);
- tex->set_z_size(depth);
- tex->set_component_type(type);
- tex->set_format(format);
- tex->set_wrap_u(get_panda_wrap_mode(wrap_u));
- tex->set_wrap_v(get_panda_wrap_mode(wrap_v));
- tex->set_wrap_w(get_panda_wrap_mode(wrap_w));
- tex->set_border_color(LColor(border_color[0], border_color[1],
- border_color[2], border_color[3]));
- tex->set_minfilter(get_panda_filter_type(minfilter));
- // tex->set_magfilter(get_panda_filter_type(magfilter));
- PTA_uchar image;
- size_t page_size = 0;
- if (!extract_texture_image(image, page_size, tex, target, page_target,
- type, compression, 0)) {
- return false;
- }
- tex->set_ram_image(image, compression, page_size);
- if (gtc->_uses_mipmaps) {
- // Also get the mipmap levels.
- GLint num_expected_levels = tex->get_expected_num_mipmap_levels();
- GLint highest_level = num_expected_levels;
- #ifndef OPENGLES
- if (is_at_least_gl_version(1, 2)) {
- glGetTexParameteriv(target, GL_TEXTURE_MAX_LEVEL, &highest_level);
- highest_level = min(highest_level, num_expected_levels);
- }
- #endif
- for (int n = 1; n <= highest_level; ++n) {
- if (!extract_texture_image(image, page_size, tex, target, page_target,
- type, compression, n)) {
- return false;
- }
- tex->set_ram_mipmap_image(n, image, page_size);
- }
- }
- return true;
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::extract_texture_image
- // Access: Protected
- // Description: Called from extract_texture_data(), this gets just
- // the image array for a particular mipmap level (or for
- // the base image).
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- extract_texture_image(PTA_uchar &image, size_t &page_size,
- Texture *tex, GLenum target, GLenum page_target,
- Texture::ComponentType type,
- Texture::CompressionMode compression, int n) {
- #ifdef OPENGLES // Extracting texture data unsupported in OpenGL ES.
- nassertr(false, false);
- return false;
- #else
- if (target == GL_TEXTURE_CUBE_MAP) {
- // A cube map, compressed or uncompressed. This we must extract
- // one page at a time.
- // If the cube map is compressed, we assume that all the
- // compressed pages are exactly the same size. OpenGL doesn't
- // make this assumption, but it happens to be true for all
- // currently extant compression schemes, and it makes things
- // simpler for us. (It also makes things much simpler for the
- // graphics hardware, so it's likely to continue to be true for a
- // while at least.)
- GLenum external_format = get_external_image_format(tex);
- GLenum pixel_type = get_component_type(type);
- page_size = tex->get_expected_ram_mipmap_page_size(n);
- if (compression != Texture::CM_off) {
- GLint image_size;
- glGetTexLevelParameteriv(page_target, n,
- GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
- nassertr(image_size <= (int)page_size, false);
- page_size = image_size;
- }
- image = PTA_uchar::empty_array(page_size * 6);
- for (int z = 0; z < 6; ++z) {
- page_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z;
- if (compression == Texture::CM_off) {
- glGetTexImage(page_target, n, external_format, pixel_type,
- image.p() + z * page_size);
- } else {
- _glGetCompressedTexImage(page_target, 0, image.p() + z * page_size);
- }
- }
- } else if (compression == Texture::CM_off) {
- // An uncompressed 1-d, 2-d, or 3-d texture.
- image = PTA_uchar::empty_array(tex->get_expected_ram_mipmap_image_size(n));
- GLenum external_format = get_external_image_format(tex);
- GLenum pixel_type = get_component_type(type);
- glGetTexImage(target, n, external_format, pixel_type, image.p());
- } else {
- // A compressed 1-d, 2-d, or 3-d texture.
- GLint image_size;
- glGetTexLevelParameteriv(target, n, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, &image_size);
- page_size = image_size / tex->get_z_size();
- image = PTA_uchar::empty_array(image_size);
- // Some drivers (ATI!) seem to try to overstuff more bytes in the
- // array than they asked us to allocate (that is, more bytes than
- // GL_TEXTURE_COMPRESSED_IMAGE_SIZE), requiring us to overallocate
- // and then copy the result into our final buffer. Sheesh.
- // We'll only do this for small textures (the ATI bug doesn't
- // *seem* to affect large textures), to save on the overhead of
- // the double-copy, and reduce risk from an overly-large alloca().
- #ifndef NDEBUG
- static const int max_trouble_buffer = 102400;
- #else
- static const int max_trouble_buffer = 1024;
- #endif
- if (image_size < max_trouble_buffer) {
- static const int extra_space = 32;
- unsigned char *buffer = (unsigned char *)alloca(image_size + extra_space);
- #ifndef NDEBUG
- // Tag the buffer with a specific byte so we can report on
- // whether that driver bug is still active.
- static unsigned char keep_token = 0x00;
- unsigned char token = ++keep_token;
- memset(buffer + image_size, token, extra_space);
- #endif
- _glGetCompressedTexImage(target, n, buffer);
- memcpy(image.p(), buffer, image_size);
- #ifndef NDEBUG
- int count = extra_space;
- while (count > 0 && buffer[image_size + count - 1] == token) {
- --count;
- }
- if (count != 0) {
- GLCAT.warning()
- << "GL graphics driver overfilled " << count
- << " bytes into a " << image_size
- << "-byte buffer provided to glGetCompressedTexImage()\n";
- }
- // This had better not equal the amount of buffer space we set
- // aside. If it does, we assume the driver might have
- // overfilled even our provided extra buffer.
- nassertr(count != extra_space, true)
- #endif // NDEBUG
- } else {
- _glGetCompressedTexImage(target, n, image.p());
- }
- }
- // Now see if we were successful.
- GLenum error_code = gl_get_error();
- if (error_code != GL_NO_ERROR) {
- GLCAT.error()
- << "Unable to extract texture for " << *tex
- << ", mipmap level " << n
- << " : " << get_error_string(error_code) << "\n";
- nassertr(false, false);
- return false;
- }
- return true;
- #endif // OPENGLES
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_point_size
- // Access: Protected
- // Description: Internally sets the point size parameters after any
- // of the properties have changed that might affect
- // this.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_point_size() {
- #ifndef OPENGLES_2
- if (!_point_perspective) {
- // Normal, constant-sized points. Here _point_size is a width in
- // pixels.
- static LVecBase3f constant(1.0f, 0.0f, 0.0f);
- _glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, constant.get_data());
- } else {
- // Perspective-sized points. Here _point_size is a width in 3-d
- // units. To arrange that, we need to figure out the appropriate
- // scaling factor based on the current viewport and projection
- // matrix.
- LVector3 height(0.0f, _point_size, 1.0f);
- height = height * _projection_mat->get_mat();
- height = height * _internal_transform->get_scale()[1];
- PN_stdfloat s = height[1] * _viewport_height / _point_size;
- if (_current_lens->is_orthographic()) {
- // If we have an orthographic lens in effect, we don't actually
- // apply a perspective transform: we just scale the points once,
- // regardless of the distance from the camera.
- LVecBase3f constant(1.0f / (s * s), 0.0f, 0.0f);
- _glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, constant.get_data());
- } else {
- // Otherwise, we give it a true perspective adjustment.
- LVecBase3f square(0.0f, 0.0f, 1.0f / (s * s));
- _glPointParameterfv(GL_POINT_DISTANCE_ATTENUATION, square.get_data());
- }
- }
- report_my_gl_errors();
- #endif
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::get_supports_cg_profile
- // Access: Public, Virtual
- // Description: Returns true if this particular GSG supports the
- // specified Cg Shader Profile.
- ////////////////////////////////////////////////////////////////////
- bool CLP(GraphicsStateGuardian)::
- get_supports_cg_profile(const string &name) const {
- #if !defined(HAVE_CG) || defined(OPENGLES)
- return false;
- #else
- CGprofile profile = cgGetProfile(name.c_str());
- if (profile == CG_PROFILE_UNKNOWN) {
- GLCAT.error() << name << ", unknown Cg-profile\n";
- return false;
- }
- return (cgGLIsProfileSupported(profile) != 0);
- #endif
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::bind_fbo
- // Access: Protected
- // Description: Binds a framebuffer object.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- bind_fbo(GLuint fbo) {
- if (_current_fbo == fbo) {
- return;
- }
- PStatGPUTimer timer(this, _fbo_bind_pcollector);
- nassertv(_glBindFramebuffer != 0);
- #if defined(OPENGLES_2)
- _glBindFramebuffer(GL_FRAMEBUFFER, fbo);
- #elif defined(OPENGLES_1)
- _glBindFramebuffer(GL_FRAMEBUFFER_OES, fbo);
- #else
- _glBindFramebuffer(GL_FRAMEBUFFER_EXT, fbo);
- #endif
- _current_fbo = fbo;
- }
- ////////////////////////////////////////////////////////////////////
- // GL stencil code section
- ////////////////////////////////////////////////////////////////////
- static int gl_stencil_operations_array[] = {
- GL_KEEP,
- GL_ZERO,
- GL_REPLACE,
- #ifdef OPENGLES_1
- GL_INCR_WRAP_OES,
- GL_DECR_WRAP_OES,
- #else
- GL_INCR_WRAP,
- GL_DECR_WRAP,
- #endif
- GL_INVERT,
- GL_INCR,
- GL_DECR,
- };
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_stencil
- // Access: Protected
- // Description: Set stencil render states.
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_stencil() {
- if (!_supports_stencil) {
- return;
- }
- const StencilAttrib *stencil;
- if (_target_rs->get_attrib(stencil)) {
- // DEBUG
- if (false) {
- GLCAT.debug() << "STENCIL STATE CHANGE\n";
- GLCAT.debug() << "\n"
- << "SRS_front_comparison_function " << (int)stencil->get_render_state(StencilAttrib::SRS_front_comparison_function) << "\n"
- << "SRS_front_stencil_fail_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation) << "\n"
- << "SRS_front_stencil_pass_z_fail_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation) << "\n"
- << "SRS_front_stencil_pass_z_pass_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation) << "\n"
- << "SRS_reference " << (int)stencil->get_render_state(StencilAttrib::SRS_reference) << "\n"
- << "SRS_read_mask " << (int)stencil->get_render_state(StencilAttrib::SRS_read_mask) << "\n"
- << "SRS_write_mask " << (int)stencil->get_render_state(StencilAttrib::SRS_write_mask) << "\n"
- << "SRS_back_comparison_function " << (int)stencil->get_render_state(StencilAttrib::SRS_back_comparison_function) << "\n"
- << "SRS_back_stencil_fail_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation) << "\n"
- << "SRS_back_stencil_pass_z_fail_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation) << "\n"
- << "SRS_back_stencil_pass_z_pass_operation " << (int)stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation) << "\n";
- }
- #ifndef OPENGLES
- if (_supports_two_sided_stencil) {
- //TODO: add support for OpenGL 2.0-style glStencilFuncSeparate.
- unsigned int back_compare;
- back_compare = stencil->get_render_state(StencilAttrib::SRS_back_comparison_function);
- if (back_compare != RenderAttrib::M_none) {
- glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
- _glActiveStencilFaceEXT(GL_BACK);
- glStencilFunc(
- PANDA_TO_GL_COMPAREFUNC(back_compare),
- stencil->get_render_state(StencilAttrib::SRS_reference),
- stencil->get_render_state(StencilAttrib::SRS_read_mask));
- glStencilOp(
- gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_back_stencil_fail_operation)],
- gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_fail_operation)],
- gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_back_stencil_pass_z_pass_operation)]
- );
- glStencilMask(stencil->get_render_state(StencilAttrib::SRS_write_mask));
- } else {
- glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
- }
- _glActiveStencilFaceEXT(GL_FRONT);
- }
- #endif // OPENGLES
- unsigned int front_compare;
- front_compare = stencil->get_render_state(StencilAttrib::SRS_front_comparison_function);
- if (front_compare != RenderAttrib::M_none) {
- glEnable(GL_STENCIL_TEST);
- glStencilFunc(
- PANDA_TO_GL_COMPAREFUNC(front_compare),
- stencil->get_render_state(StencilAttrib::SRS_reference),
- stencil->get_render_state(StencilAttrib::SRS_read_mask));
- glStencilOp(
- gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_front_stencil_fail_operation)],
- gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_fail_operation)],
- gl_stencil_operations_array[stencil->get_render_state(StencilAttrib::SRS_front_stencil_pass_z_pass_operation)]
- );
- glStencilMask(stencil->get_render_state(StencilAttrib::SRS_write_mask));
- } else {
- glDisable(GL_STENCIL_TEST);
- }
- if (stencil->get_render_state(StencilAttrib::SRS_clear)) {
- // clear stencil buffer
- glClearStencil(stencil->get_render_state(StencilAttrib::SRS_clear_value));
- glClear(GL_STENCIL_BUFFER_BIT);
- }
- } else {
- glDisable(GL_STENCIL_TEST);
- #ifndef OPENGLES
- if (_supports_two_sided_stencil) {
- glDisable(GL_STENCIL_TEST_TWO_SIDE_EXT);
- }
- #endif // OPENGLES
- }
- }
- ////////////////////////////////////////////////////////////////////
- // Function: GLGraphicsStateGuardian::do_issue_scissor
- // Access: Protected
- // Description:
- ////////////////////////////////////////////////////////////////////
- void CLP(GraphicsStateGuardian)::
- do_issue_scissor() {
- const ScissorAttrib *target_scissor;
- _target_rs->get_attrib_def(target_scissor);
- if (!target_scissor->is_off()) {
- // A non-off ScissorAttrib means to override the scissor setting
- // that was specified by the DisplayRegion.
- if (!_scissor_enabled) {
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glEnable(GL_SCISSOR_TEST)\n";
- }
- glEnable(GL_SCISSOR_TEST);
- _scissor_enabled = true;
- }
- const LVecBase4 &frame = target_scissor->get_frame();
- int x = (int)(_viewport_x + _viewport_width * frame[0] + 0.5f);
- int y = (int)(_viewport_y + _viewport_height * frame[2] + 0.5f);
- int width = (int)(_viewport_width * (frame[1] - frame[0]) + 0.5f);
- int height = (int)(_viewport_height * (frame[3] - frame[2]) + 0.5f);
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glScissor(" << x << ", " << y << ", " << width << ", " << height << ")\n";
- }
- glScissor(x, y, width, height);
- _scissor_attrib_active = true;
- } else if (_scissor_attrib_active) {
- _scissor_attrib_active = false;
- if (_scissor_array.size() > 0) {
- // Scissoring is enabled on the display region.
- // Revert to the scissor state specified in the DisplayRegion.
- #ifndef OPENGLES
- if (_supports_viewport_arrays) {
- _glScissorArrayv(0, _scissor_array.size(), _scissor_array[0].get_data());
- } else
- #endif // OPENGLES
- {
- const LVecBase4i sr = _scissor_array[0];
- glScissor(sr[0], sr[1], sr[2], sr[3]);
- }
- } else if (_scissor_enabled) {
- // The display region had no scissor enabled. Disable scissoring.
- if (GLCAT.is_spam()) {
- GLCAT.spam()
- << "glDisable(GL_SCISSOR_TEST)\n";
- }
- glDisable(GL_SCISSOR_TEST);
- _scissor_enabled = false;
- }
- }
- }
|