GXS.Scene.pas 250 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854
  1. //
  2. // The graphics engine GLXEngine. The unit of GXScene for Delphi
  3. //
  4. unit GXS.Scene;
  5. (* Base classes and structures *)
  6. interface
  7. {$I Stage.Defines.inc}
  8. uses
  9. Winapi.Windows,
  10. Winapi.OpenGL,
  11. Winapi.OpenGLext,
  12. System.Classes,
  13. System.SysUtils,
  14. System.UITypes,
  15. System.Math,
  16. FMX.Graphics,
  17. FMX.Controls,
  18. FMX.Types,
  19. FMX.Dialogs,
  20. Stage.OpenGLTokens,
  21. GXS.XCollection,
  22. Stage.VectorTypes,
  23. Stage.VectorGeometry,
  24. Stage.TextureFormat,
  25. Stage.Strings,
  26. Stage.Utils,
  27. Stage.PipelineTransform,
  28. GXS.BaseClasses,
  29. GXS.Coordinates,
  30. GXS.GeometryBB,
  31. GXS.VectorLists,
  32. GXS.Color,
  33. GXS.XOpenGL,
  34. GXS.PersistentClasses,
  35. GXS.ApplicationFileIO,
  36. GXS.Context,
  37. GXS.Silhouette,
  38. GXS.State,
  39. GXS.Graphics,
  40. GXS.Texture,
  41. GXS.RenderContextInfo,
  42. GXS.Material,
  43. GXS.Selection,
  44. GXS.ImageUtils;
  45. type
  46. // Defines which features are taken from the master object.
  47. TgxProxyObjectOption = (pooEffects, pooObjects, pooTransformation);
  48. TgxProxyObjectOptions = set of TgxProxyObjectOption;
  49. TgxCameraInvarianceMode = (cimNone, cimPosition, cimOrientation);
  50. TgxSceneViewerMode = (svmDisabled, svmDefault, svmNavigation, svmGizmo);
  51. const
  52. cDefaultProxyOptions = [pooEffects, pooObjects, pooTransformation];
  53. SCENE_REVISION = '$Revision: 2025$';
  54. SCENE_VERSION = 'v2.5 %s';
  55. type
  56. TgxNormalDirection = (ndInside, ndOutside);
  57. (* Used to describe only the changes in an object,
  58. which have to be reflected in the scene *)
  59. TgxObjectChange = (ocTransformation, ocAbsoluteMatrix, ocInvAbsoluteMatrix, ocStructure);
  60. TgxObjectChanges = set of TgxObjectChange;
  61. TgxObjectBBChange = (oBBcChild, oBBcStructure);
  62. TgxObjectBBChanges = set of TgxObjectBBChange;
  63. // Flags for design notification
  64. TgxSceneOperation = (soAdd, soRemove, soMove, soRename, soSelect, soBeginUpdate, soEndUpdate);
  65. (* Options for the rendering context.
  66. roSoftwareMode: force software rendering.
  67. roDoubleBuffer: enables double-buffering.
  68. roRenderToWindows: ignored (legacy).
  69. roTwoSideLighting: enables two-side lighting model.
  70. roStereo: enables stereo support in the driver (it needs a stereo device to test...)
  71. roDestinationAlpha: request an Alpha channel for the rendered output
  72. roNoColorBuffer: don't request a color buffer (color depth setting ignored)
  73. roNoColorBufferClear: do not clear the color buffer automatically, if the
  74. whole viewer is fully repainted each frame, this can improve framerate
  75. roNoSwapBuffers: don't perform RenderingContext.SwapBuffers after rendering
  76. roNoDepthBufferClear: do not clear the depth buffer automatically. Useful for early-z culling.
  77. roForwardContext: force OpenGL forward context *)
  78. TgxContextOption = (roSoftwareMode, roDoubleBuffer, roStencilBuffer,
  79. roRenderToWindow, roTwoSideLighting, roStereo, roDestinationAlpha,
  80. roNoColorBuffer, roNoColorBufferClear, roNoSwapBuffers,
  81. roNoDepthBufferClear, roDebugContext, roForwardContext,
  82. roOpenGL_ES2_Context);
  83. TgxContextOptions = set of TgxContextOption;
  84. // IDs for limit determination
  85. TgxLimitType = (limClipPlanes, limEvalOrder, limLights, limListNesting,
  86. limModelViewStack, limNameStack, limPixelMapTable, limProjectionStack,
  87. limTextureSize, limTextureStack, limViewportDims, limAccumAlphaBits,
  88. limAccumBlueBits, limAccumGreenBits, limAccumRedBits, limAlphaBits,
  89. limAuxBuffers, limBlueBits, limGreenBits, limRedBits, limIndexBits,
  90. limStereo, limDoubleBuffer, limSubpixelBits, limDepthBits, limStencilBits,
  91. limNbTextureUnits);
  92. TgxBaseSceneObject = class;
  93. TgxSceneObjectClass = class of TgxBaseSceneObject;
  94. TgxCustomSceneObject = class;
  95. TgxScene = class;
  96. TgxBehaviour = class;
  97. TgxBehaviourClass = class of TgxBehaviour;
  98. TgxBehaviours = class;
  99. TgxEffect = class;
  100. TgxEffectClass = class of TgxEffect;
  101. TgxEffects = class;
  102. TgxSceneBuffer = class;
  103. (* Possible styles/options for objects.
  104. Allowed styles are:
  105. osDirectDraw : object shall not make use of compiled call lists, but issue
  106. direct calls each time a render should be performed.
  107. osIgnoreDepthBuffer : object is rendered with depth test disabled,
  108. this is true for its children too.
  109. osNoVisibilityCulling : whatever the VisibilityCulling setting,
  110. it will be ignored and the object rendered *)
  111. TgxObjectStyle = (
  112. osDirectDraw,
  113. osIgnoreDepthBuffer,
  114. osNoVisibilityCulling);
  115. TgxObjectStyles = set of TgxObjectStyle;
  116. // Interface to objects that need initialization
  117. IgxInitializable = interface
  118. ['{EA40AE8E-79B3-42F5-ADF2-7A901B665E12}']
  119. procedure InitializeObject(ASender: TObject; const ARci: TgxRenderContextInfo);
  120. end;
  121. // Just a list of objects that support IGLInitializable.
  122. TgxInitializableObjectList = class(TList)
  123. private
  124. function GetItems(const Index: NativeInt): IgxInitializable;
  125. procedure PutItems(const Index: NativeInt; const Value: IgxInitializable);
  126. public
  127. function Add(const Item: IgxInitializable): Integer;
  128. property Items[const Index: NativeInt]: IgxInitializable read GetItems write PutItems; default;
  129. end;
  130. (* Base class for all scene objects.
  131. A scene object is part of scene hierarchy (each scene object can have
  132. multiple children), this hierarchy primarily defines transformations
  133. (each child coordinates are relative to its parent), but is also used
  134. for depth-sorting, bounding and visibility culling purposes.
  135. Subclasses implement either visual scene objects (that are made to be
  136. visible at runtime, like a Cube) or structural objects (that influence
  137. rendering or are used for varied structural manipulations,
  138. like the ProxyObject).
  139. To add children at runtime, use the AddNewChild method of TgxBaseSceneObject;
  140. other children manipulations methods and properties are provided (to browse,
  141. move and delete them). Using the regular TComponent methods is not encouraged. *)
  142. TgxBaseSceneObject = class(TgxCoordinatesUpdateAbleComponent)
  143. private
  144. FAbsoluteMatrix, FInvAbsoluteMatrix: TMatrix4f;
  145. FLocalMatrix: TMatrix4f;
  146. FObjectStyle: TgxObjectStyles;
  147. FListHandle: TgxListHandle; // created on 1st use
  148. FPosition: TgxCoordinates;
  149. FDirection, FUp: TgxCoordinates;
  150. FScaling: TgxCoordinates;
  151. FChanges: TgxObjectChanges;
  152. FParent: TgxBaseSceneObject;
  153. FScene: TgxScene;
  154. FBBChanges: TgxObjectBBChanges;
  155. FBoundingBoxPersonalUnscaled: THmgBoundingBox;
  156. FBoundingBoxOfChildren: THmgBoundingBox;
  157. FBoundingBoxIncludingChildren: THmgBoundingBox;
  158. FChildren: TgxPersistentObjectList; // created on 1st use
  159. FVisible: Boolean;
  160. FUpdateCount: Integer;
  161. FShowAxes: Boolean;
  162. FRotation: TgxCoordinates; // current rotation angles
  163. FIsCalculating: Boolean;
  164. FObjectsSorting: TgxObjectsSorting;
  165. FVisibilityCulling: TgxVisibilityCulling;
  166. FOnProgress: TgxProgressEvent;
  167. FOnAddedToParent: TNotifyEvent;
  168. FBehaviours: TgxBehaviours;
  169. FEffects: TgxEffects;
  170. FPickable: Boolean;
  171. FOnPicked: TNotifyEvent;
  172. FTagObject: TObject;
  173. FTagFloat: Single;
  174. ObjList: TgxPersistentObjectList;
  175. DistList: TgxSingleList;
  176. /// FOriginalFiler: TFiler; //used to allow persistent events in behaviours & effects
  177. (* If somebody could look at DefineProperties, ReadBehaviours, ReadEffects
  178. and verify code is safe to use then it could be uncommented *)
  179. function Get(Index: Integer): TgxBaseSceneObject; inline;
  180. function GetCount: Integer; inline;
  181. function GetIndex: Integer; inline;
  182. procedure SetParent(const val: TgxBaseSceneObject); inline;
  183. procedure SetIndex(aValue: Integer);
  184. procedure SetDirection(AVector: TgxCoordinates);
  185. procedure SetUp(AVector: TgxCoordinates);
  186. function GetMatrix: PMatrix4f; inline;
  187. procedure SetPosition(APosition: TgxCoordinates);
  188. procedure SetPitchAngle(AValue: Single);
  189. procedure SetRollAngle(AValue: Single);
  190. procedure SetTurnAngle(AValue: Single);
  191. procedure SetRotation(aRotation: TgxCoordinates);
  192. function GetPitchAngle: Single; inline;
  193. function GetTurnAngle: Single; inline;
  194. function GetRollAngle: Single; inline;
  195. procedure SetShowAxes(AValue: Boolean);
  196. procedure SetScaling(AValue: TgxCoordinates);
  197. procedure SetObjectsSorting(const val: TgxObjectsSorting);
  198. procedure SetVisibilityCulling(const val: TgxVisibilityCulling);
  199. procedure SetBehaviours(const val: TgxBehaviours);
  200. function GetBehaviours: TgxBehaviours;
  201. procedure SetEffects(const val: TgxEffects);
  202. function GetEffects: TgxEffects;
  203. function GetAbsoluteAffineScale: TAffineVector;
  204. function GetAbsoluteScale: TVector4f;
  205. procedure SetAbsoluteAffineScale(const Value: TAffineVector);
  206. procedure SetAbsoluteScale(const Value: TVector4f);
  207. function GetAbsoluteMatrix: TMatrix4f; inline;
  208. procedure SetAbsoluteMatrix(const Value: TMatrix4f);
  209. procedure SetBBChanges(const Value: TgxObjectBBChanges);
  210. function GetDirectAbsoluteMatrix: PMatrix4f;
  211. function GetLocalMatrix: PMatrix4f; inline;
  212. protected
  213. procedure Loaded; override;
  214. procedure SetScene(const Value: TgxScene); virtual;
  215. procedure DefineProperties(Filer: TFiler); override;
  216. procedure WriteBehaviours(stream: TStream);
  217. procedure ReadBehaviours(stream: TStream);
  218. procedure WriteEffects(stream: TStream);
  219. procedure ReadEffects(stream: TStream);
  220. procedure WriteRotations(stream: TStream);
  221. procedure ReadRotations(stream: TStream);
  222. function GetVisible: Boolean; virtual;
  223. function GetPickable: Boolean; virtual;
  224. procedure SetVisible(aValue: Boolean); virtual;
  225. procedure SetPickable(aValue: Boolean); virtual;
  226. procedure SetAbsolutePosition(const v: TVector4f);
  227. function GetAbsolutePosition: TVector4f; inline;
  228. procedure SetAbsoluteUp(const v: TVector4f);
  229. function GetAbsoluteUp: TVector4f;
  230. procedure SetAbsoluteDirection(const v: TVector4f);
  231. function GetAbsoluteDirection: TVector4f;
  232. function GetAbsoluteAffinePosition: TAffineVector;
  233. procedure SetAbsoluteAffinePosition(const Value: TAffineVector);
  234. procedure SetAbsoluteAffineUp(const v: TAffineVector);
  235. function GetAbsoluteAffineUp: TAffineVector;
  236. procedure SetAbsoluteAffineDirection(const v: TAffineVector);
  237. function GetAbsoluteAffineDirection: TAffineVector;
  238. procedure RecTransformationChanged; inline;
  239. procedure DrawAxes(var rci: TgxRenderContextInfo; pattern: Word);
  240. procedure GetChildren(AProc: TGetChildProc; Root: TComponent); override;
  241. // Should the object be considered as blended for sorting purposes?
  242. function Blended: Boolean; virtual;
  243. procedure RebuildMatrix;
  244. procedure SetName(const NewName: TComponentName); override;
  245. procedure SetParentComponent(Value: TComponent); override;
  246. procedure DestroyHandle; virtual;
  247. procedure DestroyHandles;
  248. procedure DeleteChildCameras;
  249. procedure DoOnAddedToParent; virtual;
  250. (* Used to re-calculate BoundingBoxes every time we need it.
  251. GetLocalUnscaleBB() must return the local BB, not the axis-aligned one.
  252. By default it is calculated from AxisAlignedBoundingBoxUnscaled and
  253. BarycenterAbsolutePosition, but for most objects there is a more
  254. efficient method, that's why it is virtual. *)
  255. procedure CalculateBoundingBoxPersonalUnscaled(var ANewBoundingBox: THmgBoundingBox); virtual;
  256. public
  257. constructor Create(AOwner: TComponent); override;
  258. constructor CreateAsChild(aParentOwner: TgxBaseSceneObject);
  259. destructor Destroy; override;
  260. procedure Assign(Source: TPersistent); override;
  261. (* Controls and adjusts internal optimizations based on object's style.
  262. Advanced user only. *)
  263. property ObjectStyle: TgxObjectStyles read FObjectStyle write FObjectStyle;
  264. (* Returns the handle to the object's build list.
  265. Use with caution! Some objects don't support buildlists! *)
  266. function GetHandle(var rci: TgxRenderContextInfo): Cardinal;
  267. function ListHandleAllocated: Boolean; inline;
  268. (* The local transformation (relative to parent).
  269. If you're *sure* the local matrix is up-to-date, you may use LocalMatrix
  270. for quicker access. *)
  271. procedure SetMatrix(const aValue: TMatrix4f); inline;
  272. property Matrix: PMatrix4f read GetMatrix;
  273. (* Holds the local transformation (relative to parent).
  274. If you're not *sure* the local matrix is up-to-date, use Matrix property. *)
  275. property LocalMatrix: PMatrix4f read GetLocalMatrix;
  276. (* Forces the local matrix to the specified value.
  277. AbsoluteMatrix, InverseMatrix, etc. will honour that change, but
  278. may become invalid if the specified matrix isn't orthonormal (can
  279. be used for specific rendering or projection effects).
  280. The local matrix will be reset by the next TransformationChanged,
  281. position or attitude change. *)
  282. procedure ForceLocalMatrix(const aMatrix: TMatrix4f); inline;
  283. // See AbsoluteMatrix.
  284. function AbsoluteMatrixAsAddress: PMatrix4f;
  285. (* Holds the absolute transformation matrix.
  286. If you're not *sure* the absolute matrix is up-to-date,
  287. use the AbsoluteMatrix property, this one may be nil... *)
  288. property DirectAbsoluteMatrix: PMatrix4f read GetDirectAbsoluteMatrix;
  289. (* Calculates the object's absolute inverse matrix.
  290. Multiplying an absolute coordinate with this matrix gives a local coordinate.
  291. The current implem uses transposition(AbsoluteMatrix), which is true
  292. unless you're using some scaling... *)
  293. function InvAbsoluteMatrix: TMatrix4f; inline;
  294. // See InvAbsoluteMatrix.
  295. function InvAbsoluteMatrixAsAddress: PMatrix4f;
  296. (* The object's absolute matrix by composing all local matrices.
  297. Multiplying a local coordinate with this matrix gives an absolute coordinate. *)
  298. property AbsoluteMatrix: TMatrix4f read GetAbsoluteMatrix write SetAbsoluteMatrix;
  299. // Direction vector in absolute coordinates.
  300. property AbsoluteDirection: TVector4f read GetAbsoluteDirection write SetAbsoluteDirection;
  301. property AbsoluteAffineDirection: TAffineVector read GetAbsoluteAffineDirection write SetAbsoluteAffineDirection;
  302. (* Scale vector in absolute coordinates.
  303. Warning: SetAbsoluteScale() does not work correctly at the moment. *)
  304. property AbsoluteScale: TVector4f read GetAbsoluteScale write SetAbsoluteScale;
  305. property AbsoluteAffineScale: TAffineVector read GetAbsoluteAffineScale write SetAbsoluteAffineScale;
  306. // Up vector in absolute coordinates.
  307. property AbsoluteUp: TVector4f read GetAbsoluteUp write SetAbsoluteUp;
  308. property AbsoluteAffineUp: TAffineVector read GetAbsoluteAffineUp write SetAbsoluteAffineUp;
  309. // Calculate the right vector in absolute coordinates.
  310. function AbsoluteRight: TVector4f;
  311. // Calculate the left vector in absolute coordinates.
  312. function AbsoluteLeft: TVector4f;
  313. // Computes and allows to set the object's absolute coordinates.
  314. property AbsolutePosition: TVector4f read GetAbsolutePosition write SetAbsolutePosition;
  315. property AbsoluteAffinePosition: TAffineVector read GetAbsoluteAffinePosition write SetAbsoluteAffinePosition;
  316. function AbsolutePositionAsAddress: PVector4f;
  317. // Returns the Absolute X Vector expressed in local coordinates.
  318. function AbsoluteXVector: TVector4f;
  319. // Returns the Absolute Y Vector expressed in local coordinates.
  320. function AbsoluteYVector: TVector4f;
  321. // Returns the Absolute Z Vector expressed in local coordinates.
  322. function AbsoluteZVector: TVector4f;
  323. // Converts a vector/point from absolute coordinates to local coordinates.
  324. function AbsoluteToLocal(const v: TVector4f): TVector4f; overload;
  325. // Converts a vector from absolute coordinates to local coordinates.
  326. function AbsoluteToLocal(const v: TAffineVector): TAffineVector; overload;
  327. // Converts a vector/point from local coordinates to absolute coordinates.
  328. function LocalToAbsolute(const v: TVector4f): TVector4f; overload;
  329. // Converts a vector from local coordinates to absolute coordinates.
  330. function LocalToAbsolute(const v: TAffineVector): TAffineVector; overload;
  331. // Returns the Right vector (based on Up and Direction)
  332. function Right: TVector4f; inline;
  333. // Returns the Left vector (based on Up and Direction)
  334. function LeftVector: TVector4f; inline;
  335. // Returns the Right vector (based on Up and Direction)
  336. function AffineRight: TAffineVector; inline;
  337. // Returns the Left vector (based on Up and Direction)
  338. function AffineLeftVector: TAffineVector; inline;
  339. (* Calculates the object's square distance to a point/object.
  340. pt is assumed to be in absolute coordinates,
  341. AbsolutePosition is considered as being the object position. *)
  342. function SqrDistanceTo(anObject: TgxBaseSceneObject): Single; overload;
  343. function SqrDistanceTo(const pt: TVector4f): Single; overload;
  344. function SqrDistanceTo(const pt: TAffineVector): Single; overload;
  345. (* Computes the object's distance to a point/object.
  346. Only objects AbsolutePositions are considered. *)
  347. function DistanceTo(anObject: TgxBaseSceneObject): Single; overload;
  348. function DistanceTo(const pt: TAffineVector): Single; overload;
  349. function DistanceTo(const pt: TVector4f): Single; overload;
  350. (* Calculates the object's barycenter in absolute coordinates.
  351. Default behaviour is to consider Barycenter=AbsolutePosition
  352. (whatever the number of children).
  353. SubClasses where AbsolutePosition is not the barycenter should
  354. override this method as it is used for distance calculation, during
  355. rendering for instance, and may lead to visual inconsistencies. *)
  356. function BarycenterAbsolutePosition: TVector4f; virtual;
  357. // Calculates the object's barycenter distance to a point.
  358. function BarycenterSqrDistanceTo(const pt: TVector4f): Single;
  359. (* Shall returns the object's axis aligned extensions.
  360. The dimensions are measured from object center and are expressed
  361. with scale accounted for, in the object's coordinates
  362. (not in absolute coordinates).
  363. Default value is half the object's Scale. *)
  364. function AxisAlignedDimensions: TVector4f; virtual;
  365. function AxisAlignedDimensionsUnscaled: TVector4f; virtual;
  366. (* Calculates and return the AABB for the object.
  367. The AABB is currently calculated from the BB.
  368. There is no caching scheme for them. *)
  369. function AxisAlignedBoundingBox(const AIncludeChilden: Boolean = True): TAABB;
  370. function AxisAlignedBoundingBoxUnscaled(const AIncludeChilden: Boolean = True): TAABB;
  371. function AxisAlignedBoundingBoxAbsolute(const AIncludeChilden: Boolean = True;
  372. const AUseBaryCenter: Boolean = False): TAABB;
  373. (* Advanced AABB functions that use a caching scheme.
  374. Also they include children and use BaryCenter. *)
  375. function AxisAlignedBoundingBoxEx: TAABB;
  376. function AxisAlignedBoundingBoxAbsoluteEx: TAABB;
  377. (* Calculates and return the Bounding Box for the object.
  378. The BB is calculated each time this method is invoked,
  379. based on the AxisAlignedDimensions of the object and that of its
  380. children. There is no caching scheme for them. *)
  381. function BoundingBox(const AIncludeChilden: Boolean = True; const
  382. AUseBaryCenter: Boolean = False): THmgBoundingBox;
  383. function BoundingBoxUnscaled(const AIncludeChilden: Boolean = True; const
  384. AUseBaryCenter: Boolean = False): THmgBoundingBox;
  385. function BoundingBoxAbsolute(const AIncludeChilden: Boolean = True; const
  386. AUseBaryCenter: Boolean = False): THmgBoundingBox;
  387. (* Advanced BB functions that use a caching scheme.
  388. Also they include children and use BaryCenter. *)
  389. function BoundingBoxPersonalUnscaledEx: THmgBoundingBox;
  390. function BoundingBoxOfChildrenEx: THmgBoundingBox;
  391. function BoundingBoxIncludingChildrenEx: THmgBoundingBox;
  392. // Max distance of corners of the BoundingBox.
  393. function BoundingSphereRadius: Single; inline;
  394. function BoundingSphereRadiusUnscaled: Single; inline;
  395. (* Indicates if a point is within an object.
  396. Given coordinate is an absolute coordinate.
  397. Linear or surfacic objects shall always return False.
  398. Default value is based on AxisAlignedDimension and a cube bounding. *)
  399. function PointInObject(const point: TVector4f): Boolean; virtual;
  400. (* Request to determine an intersection with a casted ray.
  401. Given coordinates & vector are in absolute coordinates, rayVector
  402. must be normalized.
  403. rayStart may be a point inside the object, allowing retrieval of
  404. the multiple intersects of the ray.
  405. When intersectXXX parameters are nil (default) implementation should
  406. take advantage of this to optimize calculus, if not, and an intersect
  407. is found, non nil parameters should be defined.
  408. The intersectNormal needs NOT be normalized by the implementations.
  409. Default value is based on bounding sphere. *)
  410. function RayCastIntersect(const rayStart, rayVector: TVector4f;
  411. intersectPoint: PVector4f = nil;
  412. intersectNormal: PVector4f = nil): Boolean; virtual;
  413. (* Request to generate silhouette outlines.
  414. Default implementation assumes the objects is a sphere of
  415. AxisAlignedDimensionUnscaled size. Subclasses may choose to return
  416. nil instead, which will be understood as an empty silhouette. *)
  417. function GenerateSilhouette(const silhouetteParameters:
  418. TgxSilhouetteParameters): TgxSilhouette; virtual;
  419. property Children[Index: Integer]: TgxBaseSceneObject read Get; default;
  420. property Count: Integer read GetCount;
  421. property Index: Integer read GetIndex write SetIndex;
  422. // Create a new scene object and add it to this object as new child
  423. function AddNewChild(AChild: TgxSceneObjectClass): TgxBaseSceneObject; virtual;
  424. // Create a new scene object and add it to this object as first child
  425. function AddNewChildFirst(AChild: TgxSceneObjectClass): TgxBaseSceneObject; virtual;
  426. procedure AddChild(AChild: TgxBaseSceneObject); virtual;
  427. function GetOrCreateBehaviour(aBehaviour: TgxBehaviourClass): TgxBehaviour;
  428. function AddNewBehaviour(aBehaviour: TgxBehaviourClass): TgxBehaviour;
  429. function GetOrCreateEffect(anEffect: TgxEffectClass): TgxEffect;
  430. function AddNewEffect(anEffect: TgxEffectClass): TgxEffect;
  431. function HasSubChildren: Boolean;
  432. procedure DeleteChildren; virtual;
  433. procedure Insert(AIndex: Integer; AChild: TgxBaseSceneObject); virtual;
  434. (* Takes a scene object out of the child list, but doesn't destroy it.
  435. If 'KeepChildren' is true its children will be kept as new children
  436. in this scene object. *)
  437. procedure Remove(AChild: TgxBaseSceneObject; keepChildren: Boolean); virtual;
  438. function IndexOfChild(AChild: TgxBaseSceneObject): Integer;
  439. function FindChild(const aName: string; ownChildrenOnly: Boolean): TgxBaseSceneObject;
  440. (* The "safe" version of this procedure checks if indexes are inside
  441. the list. If not, no exception if raised. *)
  442. procedure ExchangeChildrenSafe(anIndex1, anIndex2: Integer);
  443. (* The "regular" version of this procedure does not perform any checks
  444. and calls FChildren.Exchange directly. User should/can perform range
  445. checks manualy. *)
  446. procedure ExchangeChildren(anIndex1, anIndex2: Integer);
  447. // These procedures are safe.
  448. procedure MoveChildUp(anIndex: Integer);
  449. procedure MoveChildDown(anIndex: Integer);
  450. procedure MoveChildFirst(anIndex: Integer);
  451. procedure MoveChildLast(anIndex: Integer);
  452. procedure DoProgress(const progressTime: TgxProgressTimes); override;
  453. procedure MoveTo(newParent: TgxBaseSceneObject); virtual;
  454. procedure MoveUp;
  455. procedure MoveDown;
  456. procedure MoveFirst;
  457. procedure MoveLast;
  458. procedure BeginUpdate; inline;
  459. procedure EndUpdate; inline;
  460. (* Make object-specific geometry description here.
  461. Subclasses should MAINTAIN OpenGL states (restore the states if
  462. they were altered). *)
  463. procedure BuildList(var rci: TgxRenderContextInfo); virtual;
  464. function GetParentComponent: TComponent; override;
  465. function HasParent: Boolean; override; final;
  466. function IsUpdating: Boolean; inline;
  467. // Moves the object along the Up vector (move up/down)
  468. procedure Lift(ADistance: Single);
  469. // Moves the object along the direction vector
  470. procedure Move(ADistance: Single);
  471. // Translates the object
  472. procedure Translate(tx, ty, tz: Single);
  473. procedure MoveObjectAround(anObject: TgxBaseSceneObject; pitchDelta, turnDelta: Single);
  474. procedure MoveObjectAllAround(anObject: TgxBaseSceneObject; pitchDelta, turnDelta: Single);
  475. procedure Pitch(angle: Single);
  476. procedure Roll(angle: Single);
  477. procedure Turn(angle: Single);
  478. (* Sets all rotations to zero and restores default Direction/Up.
  479. Using this function then applying roll/pitch/turn in the order that
  480. suits you, you can give an "absolute" meaning to rotation angles
  481. (they are still applied locally though).
  482. Scale and Position are not affected. *)
  483. procedure ResetRotations;
  484. // Reset rotations and applies them back in the specified order.
  485. procedure ResetAndPitchTurnRoll(const degX, degY, degZ: Single);
  486. // Applies rotations around absolute X, Y and Z axis.
  487. procedure RotateAbsolute(const rx, ry, rz: Single); overload;
  488. // Applies rotations around the absolute given vector (angle in degrees).
  489. procedure RotateAbsolute(const axis: TAffineVector; angle: Single); overload;
  490. // Moves camera along the right vector (move left and right)
  491. procedure Slide(ADistance: Single);
  492. // Orients the object toward a target object
  493. procedure PointTo(const ATargetObject: TgxBaseSceneObject; const AUpVector: TVector4f); overload;
  494. // Orients the object toward a target absolute position
  495. procedure PointTo(const AAbsolutePosition, AUpVector: TVector4f); overload;
  496. procedure Render(var ARci: TgxRenderContextInfo);
  497. procedure DoRender(var ARci: TgxRenderContextInfo;
  498. ARenderSelf, ARenderChildren: Boolean); virtual;
  499. procedure RenderChildren(firstChildIndex, lastChildIndex: Integer;
  500. var rci: TgxRenderContextInfo);
  501. procedure StructureChanged; virtual;
  502. procedure ClearStructureChanged; inline;
  503. // Recalculate an orthonormal system
  504. procedure CoordinateChanged(Sender: TgxCustomCoordinates); override;
  505. procedure TransformationChanged; inline;
  506. procedure NotifyChange(Sender: TObject); override;
  507. property Rotation: TgxCoordinates read FRotation write SetRotation;
  508. property PitchAngle: Single read GetPitchAngle write SetPitchAngle;
  509. property RollAngle: Single read GetRollAngle write SetRollAngle;
  510. property TurnAngle: Single read GetTurnAngle write SetTurnAngle;
  511. property ShowAxes: Boolean read FShowAxes write SetShowAxes default False;
  512. property Changes: TgxObjectChanges read FChanges;
  513. property BBChanges: TgxObjectBBChanges read FBBChanges write SetBBChanges;
  514. property Parent: TgxBaseSceneObject read FParent write SetParent;
  515. property Position: TgxCoordinates read FPosition write SetPosition;
  516. property Direction: TgxCoordinates read FDirection write SetDirection;
  517. property Up: TgxCoordinates read FUp write SetUp;
  518. property Scale: TgxCoordinates read FScaling write SetScaling;
  519. property Scene: TgxScene read FScene;
  520. property Visible: Boolean read FVisible write SetVisible default True;
  521. property Pickable: Boolean read FPickable write SetPickable default True;
  522. property ObjectsSorting: TgxObjectsSorting read FObjectsSorting write
  523. SetObjectsSorting default osInherited;
  524. property VisibilityCulling: TgxVisibilityCulling read FVisibilityCulling
  525. write SetVisibilityCulling default vcInherited;
  526. property OnProgress: TgxProgressEvent read FOnProgress write FOnProgress;
  527. property OnPicked: TNotifyEvent read FOnPicked write FOnPicked;
  528. property OnAddedToParent: TNotifyEvent read FOnAddedToParent write FOnAddedToParent;
  529. property Behaviours: TgxBehaviours read GetBehaviours write SetBehaviours stored False;
  530. property Effects: TgxEffects read GetEffects write SetEffects stored False;
  531. property TagObject: TObject read FTagObject write FTagObject;
  532. published
  533. property TagFloat: Single read FTagFloat write FTagFloat;
  534. end;
  535. (* Base class for implementing behaviours in TgxScene.
  536. Behaviours are regrouped in a collection attached to a TgxBaseSceneObject,
  537. and are part of the "Progress" chain of events. Behaviours allows clean
  538. application of time-based alterations to objects (movements, shape or
  539. texture changes...).
  540. Since behaviours are implemented as classes, there are basicly two kinds
  541. of strategies for subclasses :
  542. stand-alone : the subclass does it all, and holds all necessary data
  543. (covers animation, inertia etc.)
  544. proxy : the subclass is an interface to and external, shared operator
  545. (like gravity, force-field effects etc.)
  546. Some behaviours may be cooperative (like force-fields affects inertia)
  547. or unique (e.g. only one inertia behaviour per object).
  548. NOTES : Don't forget to override the ReadFromFiler/WriteToFiler persistence
  549. methods if you add data in a subclass !
  550. Subclasses must be registered using the RegisterXCollectionItemClass function *)
  551. TgxBaseBehaviour = class(TXCollectionItem)
  552. protected
  553. procedure SetName(const val: string); override;
  554. // Override this function to write subclass data.
  555. procedure WriteToFiler(writer: TWriter); override;
  556. // Override this function to read subclass data.
  557. procedure ReadFromFiler(reader: TReader); override;
  558. (* Returns the TgxBaseSceneObject on which the behaviour should be applied.
  559. Does NOT check for nil owners. *)
  560. function OwnerBaseSceneObject: TgxBaseSceneObject;
  561. public
  562. constructor Create(AOwner: TXCollection); override;
  563. destructor Destroy; override;
  564. procedure DoProgress(const progressTime: TgxProgressTimes); virtual;
  565. end;
  566. (* Ancestor for non-rendering behaviours.
  567. This class shall never receive any properties, it's just here to differentiate
  568. rendereing and non-rendering behaviours. Rendereing behaviours are named
  569. "TgxEffect", non-rendering effects (like inertia) are simply named
  570. "TgxBehaviour". *)
  571. TgxBehaviour = class(TgxBaseBehaviour)
  572. end;
  573. (* Holds a list of TgxBehaviour objects.
  574. This object expects itself to be owned by a TgxBaseSceneObject.
  575. As a TXCollection (and contrary to a TCollection), this list can contain
  576. objects of varying class, the only constraint being that they should all
  577. be TgxBehaviour subclasses. *)
  578. TgxBehaviours = class(TXCollection)
  579. protected
  580. function GetBehaviour(Index: Integer): TgxBehaviour;
  581. public
  582. constructor Create(AOwner: TPersistent); override;
  583. function GetNamePath: string; override;
  584. class function ItemsClass: TXCollectionItemClass; override;
  585. property Behaviour[index: Integer]: TgxBehaviour read GetBehaviour; default;
  586. function CanAdd(aClass: TXCollectionItemClass): Boolean; override;
  587. procedure DoProgress(const progressTimes: TgxProgressTimes); inline;
  588. end;
  589. (* A rendering effect that can be applied to SceneObjects.
  590. ObjectEffect is a subclass of behaviour that gets a chance to Render
  591. an object-related special effect.
  592. TgxEffect should not be used as base class for custom effects,
  593. instead you should use the following base classes :
  594. TgxObjectPreEffect is rendered before owner object render
  595. TgxObjectPostEffect is rendered after the owner object render
  596. TgxObjectAfterEffect is rendered at the end of the scene rendering
  597. NOTES :
  598. Don't forget to override the ReadFromFiler/WriteToFiler persistence
  599. methods if you add data in a subclass !
  600. Subclasses must be registered using the RegisterXCollectionItemClass
  601. function *)
  602. // TgxEffectClass = class of TgxEffect;
  603. TgxEffect = class(TgxBaseBehaviour)
  604. protected
  605. // Override this function to write subclass data.
  606. procedure WriteToFiler(writer: TWriter); override;
  607. // Override this function to read subclass data.
  608. procedure ReadFromFiler(reader: TReader); override;
  609. public
  610. procedure Render(var rci: TgxRenderContextInfo); virtual;
  611. end;
  612. (* An object effect that gets rendered before owner object's render.
  613. The current OpenGL matrices and material are that of the owner object. *)
  614. TgxObjectPreEffect = class(TgxEffect)
  615. end;
  616. (* An object effect that gets rendered after owner object's render.
  617. The current OpenGL matrices and material are that of the owner object. *)
  618. TgxObjectPostEffect = class(TgxEffect)
  619. end;
  620. (* An object effect that gets rendered at scene's end.
  621. No particular OpenGL matrices or material should be assumed. *)
  622. TgxObjectAfterEffect = class(TgxEffect)
  623. end;
  624. (* Holds a list of object effects.
  625. This object expects itself to be owned by a TgxBaseSceneObject. *)
  626. TgxEffects = class(TXCollection)
  627. protected
  628. function GetEffect(Index: Integer): TgxEffect;
  629. public
  630. constructor Create(AOwner: TPersistent); override;
  631. function GetNamePath: string; override;
  632. class function ItemsClass: TXCollectionItemClass; override;
  633. property ObjectEffect[index: Integer]: TgxEffect read GetEffect; default;
  634. function CanAdd(aClass: TXCollectionItemClass): Boolean; override;
  635. procedure DoProgress(const progressTime: TgxProgressTimes);
  636. procedure RenderPreEffects(var rci: TgxRenderContextInfo); inline;
  637. // Also take care of registering after effects with the GLXceneViewer.
  638. procedure RenderPostEffects(var rci: TgxRenderContextInfo); inline;
  639. end;
  640. (* Extended base scene object class with a material property.
  641. The material allows defining a color and texture for the object, see TgxMaterial. *)
  642. TgxCustomSceneObject = class(TgxBaseSceneObject)
  643. private
  644. FMaterial: TgxMaterial;
  645. FHint: string;
  646. protected
  647. function Blended: Boolean; override;
  648. procedure SetVKMaterial(aValue: TgxMaterial); inline;
  649. procedure DestroyHandle; override;
  650. procedure Loaded; override;
  651. public
  652. constructor Create(AOwner: TComponent); override;
  653. destructor Destroy; override;
  654. procedure Assign(Source: TPersistent); override;
  655. procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
  656. property Material: TgxMaterial read FMaterial write SetVKMaterial;
  657. property Hint: string read FHint write FHint;
  658. end;
  659. (* This class shall be used only as a hierarchy root.
  660. It exists only as a container and shall never be rotated/scaled etc. as
  661. the class type is used in parenting optimizations.
  662. Shall never implement or add any functionality, the "Create" override
  663. only take cares of disabling the build list. *)
  664. TgxSceneRootObject = class(TgxBaseSceneObject)
  665. public
  666. constructor Create(AOwner: TComponent); override;
  667. end;
  668. (* Base class for objects that do not have a published "material".
  669. Note that the material is available in public properties, but isn't
  670. applied automatically before invoking BuildList.
  671. Subclassing should be reserved to structural objects and objects that
  672. have no material of their own. *)
  673. TgxImmaterialSceneObject = class(TgxCustomSceneObject)
  674. public
  675. procedure DoRender(var ARci: TgxRenderContextInfo;
  676. ARenderSelf, ARenderChildren: Boolean); override;
  677. published
  678. property ObjectsSorting;
  679. property VisibilityCulling;
  680. property Direction;
  681. property PitchAngle;
  682. property Position;
  683. property RollAngle;
  684. property Scale;
  685. property ShowAxes;
  686. property TurnAngle;
  687. property Up;
  688. property Visible;
  689. property Pickable;
  690. property OnProgress;
  691. property OnPicked;
  692. property Behaviours;
  693. property Effects;
  694. property Hint;
  695. end;
  696. (* Base class for camera invariant objects.
  697. Camera invariant objects bypass camera settings, such as camera
  698. position (object is always centered on camera) or camera orientation
  699. (object always has same orientation as camera). *)
  700. TgxCameraInvariantObject = class(TgxImmaterialSceneObject)
  701. private
  702. FCamInvarianceMode: TgxCameraInvarianceMode;
  703. protected
  704. procedure SetCamInvarianceMode(const val: TgxCameraInvarianceMode);
  705. property CamInvarianceMode: TgxCameraInvarianceMode read FCamInvarianceMode
  706. write SetCamInvarianceMode;
  707. public
  708. constructor Create(AOwner: TComponent); override;
  709. procedure Assign(Source: TPersistent); override;
  710. procedure DoRender(var ARci: TgxRenderContextInfo;
  711. ARenderSelf, ARenderChildren: Boolean); override;
  712. end;
  713. // Base class for standard scene objects. Publishes the Material property.
  714. TgxSceneObject = class(TgxCustomSceneObject)
  715. published
  716. property Material;
  717. property ObjectsSorting;
  718. property VisibilityCulling;
  719. property Direction;
  720. property PitchAngle;
  721. property Position;
  722. property RollAngle;
  723. property Scale;
  724. property ShowAxes;
  725. property TurnAngle;
  726. property Up;
  727. property Visible;
  728. property Pickable;
  729. property OnProgress;
  730. property OnPicked;
  731. property Behaviours;
  732. property Effects;
  733. property Hint;
  734. end;
  735. // Event for user-specific rendering in a TgxDirectOpenVX object.
  736. TDirectRenderEvent = procedure(Sender: TObject; var rci: TgxRenderContextInfo) of object;
  737. (* Provides a way to issue direct OpenGL calls during the rendering.
  738. You can use this object to do your specific rendering task in its OnRender
  739. event. The OpenGL calls shall restore the OpenGL states they found when
  740. entering, or exclusively use the GLMisc utility functions to alter the states. *)
  741. TgxDirectOpenGL = class(TgxImmaterialSceneObject)
  742. private
  743. FUseBuildList: Boolean;
  744. FOnRender: TDirectRenderEvent;
  745. FBlend: Boolean;
  746. protected
  747. procedure SetUseBuildList(const val: Boolean);
  748. function Blended: Boolean; override;
  749. procedure SetBlend(const val: Boolean);
  750. public
  751. constructor Create(AOwner: TComponent); override;
  752. procedure Assign(Source: TPersistent); override;
  753. procedure BuildList(var rci: TgxRenderContextInfo); override;
  754. function AxisAlignedDimensionsUnscaled: TVector4f; override;
  755. published
  756. (* Specifies if a build list be made.
  757. If True, GXScene will generate a build list (side cache),
  758. ie. OnRender will only be invoked once for the first render, or after
  759. a StructureChanged call. This is suitable for "static" geometry and
  760. will usually speed up rendering of things that don't change.
  761. If false, OnRender will be invoked for each render. This is suitable
  762. for dynamic geometry (things that change often or constantly). *)
  763. property UseBuildList: Boolean read FUseBuildList write SetUseBuildList;
  764. (* Place your specific OpenGL code here.
  765. The OpenGL calls shall restore the OpenGL states they found when
  766. entering, or exclusively use the GLMisc utility functions to alter
  767. the states. *)
  768. property OnRender: TDirectRenderEvent read FOnRender write FOnRender;
  769. (* Defines if the object uses blending.
  770. This property will allow direct OpenGL objects to be flagged as
  771. blended for object sorting purposes. *)
  772. property Blend: Boolean read FBlend write SetBlend;
  773. end;
  774. (* Scene object that allows other objects to issue rendering at some point.
  775. This object is used to specify a render point for which other components
  776. have (rendering) tasks to perform. It doesn't render anything itself
  777. and is invisible, but other components can register and be notified
  778. when the point is reached in the rendering phase.
  779. Callbacks must be explicitly unregistered. *)
  780. TgxRenderPoint = class(TgxImmaterialSceneObject)
  781. private
  782. FCallBacks: array of TDirectRenderEvent;
  783. FFreeCallBacks: array of TNotifyEvent;
  784. public
  785. constructor Create(AOwner: TComponent); override;
  786. destructor Destroy; override;
  787. procedure BuildList(var rci: TgxRenderContextInfo); override;
  788. procedure RegisterCallBack(renderEvent: TDirectRenderEvent;
  789. renderPointFreed: TNotifyEvent);
  790. procedure UnRegisterCallBack(renderEvent: TDirectRenderEvent);
  791. procedure Clear;
  792. end;
  793. (* A full proxy object.
  794. This object literally uses another object's Render method to do its own
  795. rendering, however, it has a coordinate system and a life of its own.
  796. Use it for duplicates of an object. *)
  797. TgxProxyObject = class(TgxBaseSceneObject)
  798. private
  799. FMasterObject: TgxBaseSceneObject;
  800. FProxyOptions: TgxProxyObjectOptions;
  801. protected
  802. FRendering: Boolean;
  803. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  804. procedure SetMasterObject(const val: TgxBaseSceneObject); virtual;
  805. procedure SetProxyOptions(const val: TgxProxyObjectOptions);
  806. public
  807. constructor Create(AOwner: TComponent); override;
  808. destructor Destroy; override;
  809. procedure Assign(Source: TPersistent); override;
  810. procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
  811. function BarycenterAbsolutePosition: TVector4f; override;
  812. function AxisAlignedDimensions: TVector4f; override;
  813. function AxisAlignedDimensionsUnscaled: TVector4f; override;
  814. function RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil)
  815. : Boolean; override;
  816. function GenerateSilhouette(const SilhouetteParameters: TgxSilhouetteParameters): TgxSilhouette; override;
  817. published
  818. // Specifies the Master object which will be proxy'ed.
  819. property MasterObject: TgxBaseSceneObject read FMasterObject write SetMasterObject;
  820. // Specifies how and what is proxy'ed.
  821. property ProxyOptions: TgxProxyObjectOptions read FProxyOptions write SetProxyOptions default cDefaultProxyOptions;
  822. property ObjectsSorting;
  823. property Direction;
  824. property PitchAngle;
  825. property Position;
  826. property RollAngle;
  827. property Scale;
  828. property ShowAxes;
  829. property TurnAngle;
  830. property Up;
  831. property Visible;
  832. property Pickable;
  833. property OnProgress;
  834. property OnPicked;
  835. property Behaviours;
  836. end;
  837. TgxProxyObjectClass = class of TgxProxyObject;
  838. (* Defines the various styles for lightsources.
  839. lsSpot : a spot light, oriented and with a cutoff zone (note that if
  840. cutoff is 180, the spot is rendered as an omni source)
  841. lsOmni : an omnidirectionnal source, punctual and sending light in
  842. all directions uniformously
  843. lsParallel : a parallel light, oriented as the light source is (this
  844. type of light can help speed up rendering) *)
  845. TgxLightStyle = (lsSpot, lsOmni, lsParallel, lsParallelSpot);
  846. (* Standard light source.
  847. The standard light source covers spotlights, omnidirectionnal and
  848. parallel sources (see TLightStyle).
  849. Lights are colored, have distance attenuation parameters and are turned
  850. on/off through their Shining property.
  851. Lightsources are managed in a specific object by the TgxScene for rendering
  852. purposes. The maximum number of light source in a scene is limited by the
  853. OpenGL implementation (8 lights are supported under most ICDs), though the
  854. more light you use, the slower rendering may get. If you want to render
  855. many more light/lightsource, you may have to resort to other techniques
  856. like lightmapping. *)
  857. TgxLightSource = class(TgxBaseSceneObject)
  858. private
  859. FLightID: Cardinal;
  860. FSpotDirection: TgxCoordinates;
  861. FSpotExponent, FSpotCutOff: Single;
  862. FConstAttenuation, FLinearAttenuation, FQuadraticAttenuation: Single;
  863. FShining: Boolean;
  864. FAmbient, FDiffuse, FSpecular: TgxColor;
  865. FLightStyle: TgxLightStyle;
  866. protected
  867. procedure SetAmbient(aValue: TgxColor);
  868. procedure SetDiffuse(aValue: TgxColor);
  869. procedure SetSpecular(aValue: TgxColor);
  870. procedure SetConstAttenuation(aValue: Single);
  871. procedure SetLinearAttenuation(aValue: Single);
  872. procedure SetQuadraticAttenuation(aValue: Single);
  873. procedure SetShining(aValue: Boolean);
  874. procedure SetSpotDirection(AVector: TgxCoordinates);
  875. procedure SetSpotExponent(aValue: Single);
  876. procedure SetSpotCutOff(const val: Single);
  877. procedure SetLightStyle(const val: TgxLightStyle);
  878. public
  879. constructor Create(AOwner: TComponent); override;
  880. destructor Destroy; override;
  881. procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
  882. // light sources have different handle types than normal scene objects
  883. function RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil)
  884. : Boolean; override;
  885. procedure CoordinateChanged(Sender: TgxCustomCoordinates); override;
  886. function GenerateSilhouette(const silhouetteParameters: TgxSilhouetteParameters): TgxSilhouette; override;
  887. property LightID: Cardinal read FLightID;
  888. function Attenuated: Boolean;
  889. published
  890. property Ambient: TgxColor read FAmbient write SetAmbient;
  891. property ConstAttenuation: Single read FConstAttenuation write SetConstAttenuation;
  892. property Diffuse: TgxColor read FDiffuse write SetDiffuse;
  893. property LinearAttenuation: Single read FLinearAttenuation write SetLinearAttenuation;
  894. property QuadraticAttenuation: Single read FQuadraticAttenuation write SetQuadraticAttenuation;
  895. property Position;
  896. property LightStyle: TgxLightStyle read FLightStyle write SetLightStyle default lsSpot;
  897. property Shining: Boolean read FShining write SetShining default True;
  898. property Specular: TgxColor read FSpecular write SetSpecular;
  899. property SpotCutOff: Single read FSpotCutOff write SetSpotCutOff;
  900. property SpotDirection: TgxCoordinates read FSpotDirection write SetSpotDirection;
  901. property SpotExponent: Single read FSpotExponent write SetSpotExponent;
  902. property OnProgress;
  903. end;
  904. TgxCameraStyle = (csPerspective, csOrthogonal, csOrtho2D, csCustom, csInfinitePerspective, csPerspectiveKeepFOV);
  905. TgxCameraKeepFOVMode = (ckmHorizontalFOV, ckmVerticalFOV);
  906. TgxOnCustomPerspective = procedure(const viewport: TRectangle; width, height: Integer; DPI: Integer; var viewPortRadius: Single)
  907. of object;
  908. (* Camera object.
  909. This object is commonly referred by TgxSceneViewer and defines a position,
  910. direction, focal length, depth of view... all the properties needed for
  911. defining a point of view and optical characteristics. *)
  912. TgxCamera = class(TgxBaseSceneObject)
  913. private
  914. FFocalLength: Single;
  915. FDepthOfView: Single;
  916. FNearPlane: Single; // nearest distance to the camera
  917. FNearPlaneBias: Single; // scaling bias applied to near plane
  918. FViewPortRadius: Single; // viewport bounding radius per distance unit
  919. FTargetObject: TgxBaseSceneObject;
  920. FLastDirection: TVector4f; // Not persistent
  921. FCameraStyle: TgxCameraStyle;
  922. FKeepFOVMode: TgxCameraKeepFOVMode;
  923. FSceneScale: Single;
  924. FDeferredApply: TNotifyEvent;
  925. FOnCustomPerspective: TgxOnCustomPerspective;
  926. FDesign: Boolean;
  927. FFOVY, FFOVX: Double;
  928. protected
  929. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  930. procedure SetTargetObject(const val: TgxBaseSceneObject);
  931. procedure SetDepthOfView(aValue: Single);
  932. procedure SetFocalLength(aValue: Single);
  933. procedure SetCameraStyle(const val: TgxCameraStyle);
  934. procedure SetKeepFOVMode(const val: TgxCameraKeepFOVMode);
  935. procedure SetSceneScale(Value: Single);
  936. function StoreSceneScale: Boolean;
  937. procedure SetNearPlaneBias(Value: Single);
  938. function StoreNearPlaneBias: Boolean;
  939. public
  940. constructor Create(AOwner: TComponent); override;
  941. destructor Destroy; override;
  942. procedure Assign(Source: TPersistent); override;
  943. (* Nearest clipping plane for the frustum.
  944. This value depends on the FocalLength and DepthOfView fields and
  945. is calculated to minimize Z-Buffer crawling as suggested by the OpenGL documentation. *)
  946. property NearPlane: Single read FNearPlane;
  947. // Apply camera transformation
  948. procedure Apply;
  949. procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
  950. function RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil)
  951. : Boolean; override;
  952. procedure ApplyPerspective(const AViewport: TRectangle; AWidth, AHeight: Integer; ADPI: Integer);
  953. procedure AutoLeveling(Factor: Single);
  954. procedure Reset(aSceneBuffer: TgxSceneBuffer);
  955. // Position the camera so that the whole scene can be seen
  956. procedure ZoomAll(aSceneBuffer: TgxSceneBuffer);
  957. procedure RotateObject(obj: TgxBaseSceneObject; pitchDelta, turnDelta: Single; rollDelta: Single = 0);
  958. procedure RotateTarget(pitchDelta, turnDelta: Single; rollDelta: Single = 0);
  959. (* Change camera's position to make it move around its target.
  960. If TargetObject is nil, nothing happens. This method helps in quickly
  961. implementing camera controls. Camera's Up and Direction properties are unchanged.
  962. Angle deltas are in degrees, camera parent's coordinates should be identity.
  963. Tip : make the camera a child of a "target" dummycube and make
  964. it a target the dummycube. Now, to pan across the scene, just move
  965. the dummycube, to change viewing angle, use this method. *)
  966. procedure MoveAroundTarget(pitchDelta, turnDelta: Single);
  967. (* Change camera's position to make it move all around its target.
  968. If TargetObject is nil, nothing happens. This method helps in quickly
  969. implementing camera controls. Camera's Up and Direction properties are changed.
  970. Angle deltas are in degrees. *)
  971. procedure MoveAllAroundTarget(pitchDelta, turnDelta: Single);
  972. // Moves the camera in eye space coordinates.
  973. procedure MoveInEyeSpace(forwardDistance, rightDistance, upDistance: Single);
  974. // Moves the target in eye space coordinates.
  975. procedure MoveTargetInEyeSpace(forwardDistance, rightDistance, upDistance: Single);
  976. // Computes the absolute vector corresponding to the eye-space translations.
  977. function AbsoluteEyeSpaceVector(forwardDistance, rightDistance, upDistance: Single): TVector4f;
  978. (* Adjusts distance from camera to target by applying a ratio.
  979. If TargetObject is nil, nothing happens. This method helps in quickly
  980. implementing camera controls. Only the camera's position is changed. *)
  981. procedure AdjustDistanceToTarget(distanceRatio: Single);
  982. (* Returns the distance from camera to target.
  983. If TargetObject is nil, returns 1. *)
  984. function DistanceToTarget: Single;
  985. (* Computes the absolute normalized vector to the camera target.
  986. If no target is defined, AbsoluteDirection is returned. *)
  987. function AbsoluteVectorToTarget: TVector4f;
  988. (* Computes the absolute normalized right vector to the camera target.
  989. If no target is defined, AbsoluteRight is returned. *)
  990. function AbsoluteRightVectorToTarget: TVector4f;
  991. (* Computes the absolute normalized up vector to the camera target.
  992. If no target is defined, AbsoluteUpt is returned. *)
  993. function AbsoluteUpVectorToTarget: TVector4f;
  994. (* Calculate an absolute translation vector from a screen vector.
  995. Ratio is applied to both screen delta, planeNormal should be the
  996. translation plane's normal. *)
  997. function ScreenDeltaToVector(deltaX, deltaY: Integer; ratio: Single; const planeNormal: TVector4f): TVector4f;
  998. // Same as ScreenDeltaToVector but optimized for XY plane.
  999. function ScreenDeltaToVectorXY(deltaX, deltaY: Integer; ratio: Single): TVector4f;
  1000. // Same as ScreenDeltaToVector but optimized for XZ plane.
  1001. function ScreenDeltaToVectorXZ(deltaX, deltaY: Integer; ratio: Single): TVector4f;
  1002. // Same as ScreenDeltaToVector but optimized for YZ plane.
  1003. function ScreenDeltaToVectorYZ(deltaX, deltaY: Integer; ratio: Single): TVector4f;
  1004. // Returns true if a point is in front of the camera.
  1005. function PointInFront(const point: TVector4f): Boolean; overload;
  1006. (* Calculates the field of view in degrees, given a viewport dimension
  1007. (width or height). F.i. you may wish to use the minimum of the two. *)
  1008. function GetFieldOfView(const AViewportDimension: Single): Single;
  1009. (* Sets the FocalLength in degrees, given a field of view and a viewport
  1010. dimension (width or height). *)
  1011. procedure SetFieldOfView(const AFieldOfView, AViewportDimension: Single);
  1012. published
  1013. (* Depth of field/view.
  1014. Adjusts the maximum distance, beyond which objects will be clipped
  1015. (ie. not visisble).
  1016. You must adjust this value if you are experiencing disappearing
  1017. objects (increase the value) of Z-Buffer crawling (decrease the
  1018. value). Z-Buffer crawling happens when depth of view is too large
  1019. and the Z-Buffer precision cannot account for all that depth
  1020. accurately : objects farther overlap closer objects and vice-versa.
  1021. Note that this value is ignored in cSOrtho2D mode. *)
  1022. property DepthOfView: Single read FDepthOfView write SetDepthOfView;
  1023. (* Focal Length of the camera.
  1024. Adjusting this value allows for lens zooming effects (use SceneScale
  1025. for linear zooming). This property affects near/far planes clipping. *)
  1026. property FocalLength: Single read FFocalLength write SetFocalLength;
  1027. (* Scene scaling for camera point.
  1028. This is a linear 2D scaling of the camera's output, allows for
  1029. linear zooming (use FocalLength for lens zooming). *)
  1030. property SceneScale: Single read FSceneScale write SetSceneScale stored StoreSceneScale;
  1031. (* Scaling bias applied to near-plane calculation.
  1032. Values inferior to one will move the nearplane nearer, and also
  1033. reduce medium/long range Z-Buffer precision, values superior
  1034. to one will move the nearplane farther, and also improve medium/long
  1035. range Z-Buffer precision. *)
  1036. property NearPlaneBias: Single read FNearPlaneBias write SetNearPlaneBias stored StoreNearPlaneBias;
  1037. (* If set, camera will point to this object.
  1038. When camera is pointing an object, the Direction vector is ignored
  1039. and the Up vector is used as an absolute vector to the up. *)
  1040. property TargetObject: TgxBaseSceneObject read FTargetObject write SetTargetObject;
  1041. (* Adjust the camera style.
  1042. Three styles are available :
  1043. csPerspective, the default value for perspective projection
  1044. csOrthogonal, for orthogonal (or isometric) projection.
  1045. csOrtho2D, setups orthogonal 2D projection in which 1 unit
  1046. (in x or y) represents 1 pixel.
  1047. csInfinitePerspective, for perspective view without depth limit.
  1048. csKeepCamAnglePerspective, for perspective view with keeping aspect on view resize.
  1049. csCustom, setup is deferred to the OnCustomPerspective event. *)
  1050. property CameraStyle: TgxCameraStyle read FCameraStyle write SetCameraStyle default csPerspective;
  1051. (* Keep camera angle mode.
  1052. When CameraStyle is csKeepCamAnglePerspective, select which camera angle you want to keep.
  1053. kaHeight, for Keep Height oriented camera angle
  1054. kaWidth, for Keep Width oriented camera angle *)
  1055. property KeepFOVMode: TgxCameraKeepFOVMode read FKeepFOVMode write SetKeepFOVMode default ckmHorizontalFOV;
  1056. (* Custom perspective event.
  1057. This event allows you to specify your custom perpective, either
  1058. with a glFrustrum, a glOrtho or whatever method suits you.
  1059. You must compute viewPortRadius for culling to work.
  1060. This event is only called if CameraStyle is csCustom. *)
  1061. property OnCustomPerspective: TgxOnCustomPerspective read FOnCustomPerspective write FOnCustomPerspective;
  1062. property Position;
  1063. property Direction;
  1064. property Up;
  1065. property OnProgress;
  1066. end;
  1067. (* Scene object.
  1068. The scene contains the scene description (lights, geometry...), which is
  1069. basicly a hierarchical scene graph made of TgxBaseSceneObject. It will
  1070. usually contain one or more TgxCamera object, which can be referred by
  1071. a Viewer component for rendering purposes.
  1072. The scene's objects can be accessed directly from Delphi code (as regular
  1073. components), but those are edited with a specific editor (double-click
  1074. on the TgxScene component at design-time to invoke it). To add objects
  1075. at runtime, use the AddNewChild method of TgxBaseSceneObject. *)
  1076. TgxScene = class(TgxUpdateAbleComponent)
  1077. private
  1078. FUpdateCount: Integer;
  1079. FObjects: TgxSceneRootObject;
  1080. FBaseContext: TgxContext; // reference, not owned!
  1081. FLights, FBuffers: TgxPersistentObjectList;
  1082. FCurrentCamera: TgxCamera;
  1083. FCurrentBuffer: TgxSceneBuffer;
  1084. FObjectsSorting: TgxObjectsSorting;
  1085. FVisibilityCulling: TgxVisibilityCulling;
  1086. FOnBeforeProgress: TgxProgressEvent;
  1087. FOnProgress: TgxProgressEvent;
  1088. FCurrentDeltaTime: Double;
  1089. FInitializableObjects: TgxInitializableObjectList;
  1090. protected
  1091. procedure AddLight(aLight: TgxLightSource);
  1092. procedure RemoveLight(aLight: TgxLightSource);
  1093. // Adds all lights in the subtree (anObj included)
  1094. procedure AddLights(anObj: TgxBaseSceneObject);
  1095. // Removes all lights in the subtree (anObj included)
  1096. procedure RemoveLights(anObj: TgxBaseSceneObject);
  1097. procedure GetChildren(AProc: TGetChildProc; Root: TComponent); override;
  1098. procedure SetChildOrder(AChild: TComponent; Order: Integer); override;
  1099. procedure SetObjectsSorting(const val: TgxObjectsSorting);
  1100. procedure SetVisibilityCulling(const val: TgxVisibilityCulling);
  1101. procedure ReadState(reader: TReader); override;
  1102. public
  1103. constructor Create(AOwner: TComponent); override;
  1104. destructor Destroy; override;
  1105. procedure BeginUpdate;
  1106. procedure EndUpdate;
  1107. function IsUpdating: Boolean;
  1108. procedure AddBuffer(aBuffer: TgxSceneBuffer);
  1109. procedure RemoveBuffer(aBuffer: TgxSceneBuffer);
  1110. procedure SetupLights(maxLights: Integer);
  1111. procedure NotifyChange(Sender: TObject); override;
  1112. procedure Progress(const deltaTime, newTime: Double);
  1113. function FindSceneObject(const aName: string): TgxBaseSceneObject;
  1114. (* Calculates, finds and returns the first object intercepted by the ray.
  1115. Returns nil if no intersection was found. This function will be
  1116. accurate only for objects that overrided their RayCastIntersect
  1117. method with accurate code, otherwise, bounding sphere intersections
  1118. will be returned. *)
  1119. function RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil)
  1120. : TgxBaseSceneObject; virtual;
  1121. procedure ShutdownAllLights;
  1122. // Saves the scene to a file (recommended extension : .GLS)
  1123. procedure SaveToFile(const fileName: string);
  1124. (* Load the scene from a file.
  1125. Existing objects/lights/cameras are freed, then the file is loaded.
  1126. Delphi's IDE is not handling this behaviour properly yet, ie. if
  1127. you load a scene in the IDE, objects will be properly loaded, but
  1128. no declare will be placed in the code. *)
  1129. procedure LoadFromFile(const fileName: string);
  1130. procedure SaveToStream(aStream: TStream);
  1131. procedure LoadFromStream(aStream: TStream);
  1132. // Saves the scene to a text file
  1133. procedure SaveToTextFile(const fileName: string);
  1134. (* Load the scene from a text files.
  1135. See LoadFromFile for details. *)
  1136. procedure LoadFromTextFile(const fileName: string);
  1137. property CurrentCamera: TgxCamera read FCurrentCamera;
  1138. property Lights: TgxPersistentObjectList read FLights;
  1139. property Objects: TgxSceneRootObject read FObjects;
  1140. property CurrentBuffer: TgxSceneBuffer read FCurrentBuffer;
  1141. (* List of objects that request to be initialized when rendering context is active.
  1142. They are removed automaticly from this list once initialized. *)
  1143. property InitializableObjects: TgxInitializableObjectList read FInitializableObjects;
  1144. property CurrentDeltaTime: Double read FCurrentDeltaTime;
  1145. published
  1146. // Defines default ObjectSorting option for scene objects.
  1147. property ObjectsSorting: TgxObjectsSorting read FObjectsSorting write SetObjectsSorting default osRenderBlendedLast;
  1148. // Defines default VisibilityCulling option for scene objects.
  1149. property VisibilityCulling: TgxVisibilityCulling read FVisibilityCulling write SetVisibilityCulling default vcNone;
  1150. property OnBeforeProgress: TgxProgressEvent read FOnBeforeProgress write FOnBeforeProgress;
  1151. property OnProgress: TgxProgressEvent read FOnProgress write FOnProgress;
  1152. end;
  1153. TgxFogMode = (fmLinear, fmExp, fmExp2);
  1154. (* Fog distance calculation mode.
  1155. fdDefault: let OpenGL use its default formula
  1156. fdEyeRadial: uses radial "true" distance (best quality)
  1157. fdEyePlane: uses the distance to the projection plane (same as Z-Buffer, faster)
  1158. Requires support of GL_NV_fog_distance extension, otherwise, it is ignored. *)
  1159. TgxFogDistance = (fdDefault, fdEyeRadial, fdEyePlane);
  1160. (* Parameters for fog environment in a scene.
  1161. The fog descibed by this object is a distance-based fog, ie. the "intensity"
  1162. of the fog is given by a formula depending solely on the distance, this
  1163. intensity is used for blending to a fixed color. *)
  1164. TgxFogEnvironment = class(TgxUpdateAbleObject)
  1165. private
  1166. FSceneBuffer: TgxSceneBuffer;
  1167. FFogColor: TgxColor; // alpha value means the fog density
  1168. FFogStart, FFogEnd: Single;
  1169. FFogMode: TgxFogMode;
  1170. FFogDistance: TgxFogDistance;
  1171. protected
  1172. procedure SetFogColor(Value: TgxColor);
  1173. procedure SetFogStart(Value: Single);
  1174. procedure SetFogEnd(Value: Single);
  1175. procedure SetFogMode(Value: TgxFogMode);
  1176. procedure SetFogDistance(const val: TgxFogDistance);
  1177. public
  1178. constructor Create(AOwner: TPersistent); override;
  1179. destructor Destroy; override;
  1180. procedure ApplyFog;
  1181. procedure Assign(Source: TPersistent); override;
  1182. function IsAtDefaultValues: Boolean;
  1183. published
  1184. // Color of the fog when it is at 100% intensity.
  1185. property FogColor: TgxColor read FFogColor write SetFogColor;
  1186. // Minimum distance for fog, what is closer is not affected.
  1187. property FogStart: Single read FFogStart write SetFogStart;
  1188. // Maximum distance for fog, what is farther is at 100% fog intensity.
  1189. property FogEnd: Single read FFogEnd write SetFogEnd;
  1190. // The formula used for converting distance to fog intensity.
  1191. property FogMode: TgxFogMode read FFogMode write SetFogMode default fmLinear;
  1192. (* Adjusts the formula used for calculating fog distances.
  1193. This option is honoured if and only if the OpenGL ICD supports the
  1194. GL_NV_fog_distance extension, otherwise, it is ignored.
  1195. fdDefault: let OpenGL use its default formula
  1196. fdEyeRadial: uses radial "true" distance (best quality)
  1197. fdEyePlane: uses the distance to the projection plane (same as Z-Buffer, faster) *)
  1198. property FogDistance: TgxFogDistance read FFogDistance write SetFogDistance default fdDefault;
  1199. end;
  1200. TgxDepthPrecision = (dpDefault, dp16bits, dp24bits, dp32bits);
  1201. TgxColorDepth = (cdDefault, cd8bits, cd16bits, cd24bits, cdFloat64bits, cdFloat128bits); // float_type
  1202. TgxShadeModel = (smDefault, smSmooth, smFlat);
  1203. // Encapsulates an OpenGL frame/rendering buffer.
  1204. TgxSceneBuffer = class(TgxUpdateAbleObject)
  1205. private
  1206. // Internal state
  1207. FRendering: Boolean;
  1208. FRenderingContext: TgxContext;
  1209. FAfterRenderEffects: TgxPersistentObjectList;
  1210. FViewMatrixStack: array of TMatrix4f;
  1211. FProjectionMatrixStack: array of TMatrix4f;
  1212. FBaseProjectionMatrix: TMatrix4f;
  1213. FCameraAbsolutePosition: TVector4f;
  1214. FViewPort: TRectangle;
  1215. FSelector: TgxBaseSelectTechnique;
  1216. // Options & User Properties
  1217. FFaceCulling, FFogEnable, FLighting: Boolean;
  1218. FDepthTest: Boolean;
  1219. FBackgroundColor: TColor;
  1220. FBackgroundAlpha: Single;
  1221. FAmbientColor: TgxColor;
  1222. FAntiAliasing: TgxAntiAliasing;
  1223. FDepthPrecision: TgxDepthPrecision;
  1224. FColorDepth: TgxColorDepth;
  1225. FContextOptions: TgxContextOptions;
  1226. FShadeModel: TgxShadeModel;
  1227. FRenderDPI: Integer;
  1228. FFogEnvironment: TgxFogEnvironment;
  1229. FAccumBufferBits: Integer;
  1230. FLayer: TgxContextLayer;
  1231. // Cameras
  1232. FCamera: TgxCamera;
  1233. // Freezing
  1234. FFreezeBuffer: Pointer;
  1235. FFreezed: Boolean;
  1236. FFreezedViewPort: TRectangle;
  1237. // Monitoring
  1238. FFrameCount: Longint;
  1239. FFramesPerSecond: Single;
  1240. FFirstPerfCounter: Int64;
  1241. FLastFrameTime: Single;
  1242. // Events
  1243. FOnChange: TNotifyEvent;
  1244. FOnStructuralChange: TNotifyEvent;
  1245. FOnPrepareGLContext: TNotifyEvent;
  1246. FBeforeRender: TNotifyEvent;
  1247. FViewerBeforeRender: TNotifyEvent;
  1248. FPostRender: TNotifyEvent;
  1249. FAfterRender: TNotifyEvent;
  1250. FInitiateRendering: TDirectRenderEvent;
  1251. FWrapUpRendering: TDirectRenderEvent;
  1252. procedure SetLayer(const Value: TgxContextLayer);
  1253. protected
  1254. procedure SetBackgroundColor(AColor: TColor);
  1255. procedure SetBackgroundAlpha(alpha: Single);
  1256. procedure SetAmbientColor(AColor: TgxColor);
  1257. function GetLimit(Which: TgxLimitType): Integer;
  1258. procedure SetCamera(ACamera: TgxCamera);
  1259. procedure SetContextOptions(Options: TgxContextOptions);
  1260. procedure SetDepthTest(aValue: Boolean);
  1261. procedure SetFaceCulling(aValue: Boolean);
  1262. procedure SetLighting(aValue: Boolean);
  1263. procedure SetAntiAliasing(const val: TgxAntiAliasing);
  1264. procedure SetDepthPrecision(const val: TgxDepthPrecision);
  1265. procedure SetColorDepth(const val: TgxColorDepth);
  1266. procedure SetShadeModel(const val: TgxShadeModel);
  1267. procedure SetFogEnable(aValue: Boolean);
  1268. procedure SetFogEnvironment(aValue: TgxFogEnvironment);
  1269. function StoreFog: Boolean;
  1270. procedure SetAccumBufferBits(const val: Integer);
  1271. procedure PrepareRenderingMatrices(const AViewport: TRectangle; resolution: Integer; pickingRect: PRect = nil);
  1272. procedure DoBaseRender(const AViewport: TRectangle; resolution: Integer; drawState: TGXDrawState;
  1273. baseObject: TgxBaseSceneObject);
  1274. procedure SetupRenderingContext(Context: TgxContext);
  1275. procedure SetupRCOptions(Context: TgxContext);
  1276. procedure PrepareGLContext;
  1277. procedure DoChange;
  1278. procedure DoStructuralChange;
  1279. // DPI for current/last render
  1280. property RenderDPI: Integer read FRenderDPI;
  1281. property OnPrepareGLContext: TNotifyEvent read FOnPrepareGLContext write FOnPrepareGLContext;
  1282. public
  1283. constructor Create(AOwner: TPersistent); override;
  1284. destructor Destroy; override;
  1285. procedure NotifyChange(Sender: TObject); override;
  1286. procedure CreateRC(AWindowHandle: THandle; memoryContext: Boolean; // in VCL -> HWND
  1287. BufferCount: Integer = 1); overload;
  1288. procedure ClearBuffers;
  1289. procedure DestroyRC;
  1290. function RCInstantiated: Boolean;
  1291. procedure Resize(newLeft, newTop, newWidth, newHeight: Integer);
  1292. // Indicates hardware acceleration support
  1293. function Acceleration: TgxContextAcceleration;
  1294. // ViewPort for current/last render
  1295. property viewport: TRectangle read FViewPort;
  1296. // Fills the PickList with objects in Rect area
  1297. procedure PickObjects(const rect: TRect; pickList: TgxPickList; objectCountGuess: Integer);
  1298. (* Returns a PickList with objects in Rect area.
  1299. Returned list should be freed by caller.
  1300. Objects are sorted by depth (nearest objects first). *)
  1301. function GetPickedObjects(const rect: TRect; objectCountGuess: Integer = 64): TgxPickList;
  1302. // Returns the nearest object at x, y coordinates or nil if there is none
  1303. function GetPickedObject(x, y: Integer): TgxBaseSceneObject;
  1304. // Returns the color of the pixel at x, y in the frame buffer
  1305. function GetPixelColor(x, y: Integer): TColor;
  1306. (* Returns the raw depth (Z buffer) of the pixel at x, y in the frame buffer.
  1307. This value does not map to the actual eye-object distance, but to
  1308. a depth buffer value in the [0; 1] range. *)
  1309. function GetPixelDepth(x, y: Integer): Single;
  1310. (* Converts a raw depth (Z buffer value) to frustrum distance.
  1311. This calculation is only accurate for the pixel at the centre of the viewer,
  1312. because it does not take into account that the corners of the frustrum
  1313. are further from the eye than its centre. *)
  1314. function PixelDepthToDistance(aDepth: Single): Single;
  1315. (* Converts a raw depth (Z buffer value) to world distance.
  1316. It also compensates for the fact that the corners of the frustrum
  1317. are further from the eye, than its centre. *)
  1318. function PixelToDistance(x, y: Integer): Single;
  1319. // Design time notification
  1320. procedure NotifyMouseMove(Shift: TShiftState; x, y: Single);
  1321. (* Renders the scene on the viewer.
  1322. You do not need to call this method, unless you explicitly want a
  1323. render at a specific time. If you just want the control to get
  1324. refreshed, use Invalidate instead. *)
  1325. procedure Render(baseObject: TgxBaseSceneObject); overload;
  1326. procedure Render; overload;
  1327. procedure RenderScene(aScene: TgxScene; const viewPortSizeX, viewPortSizeY: Integer; drawState: TGXDrawState;
  1328. baseObject: TgxBaseSceneObject);
  1329. (* Render the scene to a bitmap at given DPI.
  1330. DPI = "dots per inch".
  1331. The "magic" DPI of the screen is 96 under Windows. *)
  1332. procedure RenderToBitmap(ABitmap: TBitmap; DPI: Integer = 0);
  1333. (* Render the scene to a bitmap at given DPI and saves it to a file.
  1334. DPI = "dots per inch".
  1335. The "magic" DPI of the screen is 96 under Windows. *)
  1336. procedure RenderToFile(const AFile: string; DPI: Integer = 0); overload;
  1337. (* Renders to bitmap of given size, then saves it to a file.
  1338. DPI is adjusted to make the bitmap similar to the viewer. *)
  1339. procedure RenderToFile(const AFile: string; bmpWidth, bmpHeight: Integer); overload;
  1340. (* Creates a TgxBitmap32 that is a snapshot of current OpenGL content.
  1341. When possible, use this function instead of RenderToBitmap, it won't
  1342. request a redraw and will be significantly faster.
  1343. The returned TgxBitmap32 should be freed by calling code. *)
  1344. function CreateSnapShot: TgxImage;
  1345. // Creates a bitmap that is a snapshot of current graphic content.
  1346. function CreateSnapShotBitmap: TBitmap;
  1347. procedure CopyToTexture(aTexture: TgxTexture); overload;
  1348. procedure CopyToTexture(aTexture: TgxTexture; xSrc, ySrc, AWidth, AHeight: Integer; xDest, yDest: Integer;
  1349. glCubeFace: GLEnum = 0); overload;
  1350. // Save as raw float data to a file
  1351. procedure SaveAsFloatToFile(const aFilename: string);
  1352. // Event reserved for viewer-specific uses.
  1353. property ViewerBeforeRender: TNotifyEvent read FViewerBeforeRender write FViewerBeforeRender stored False;
  1354. procedure SetViewPort(x, y, W, H: Integer);
  1355. function width: Integer;
  1356. function height: Integer;
  1357. // Indicates if the Viewer is "frozen".
  1358. property Freezed: Boolean read FFreezed;
  1359. (* Freezes rendering leaving the last rendered scene on the buffer. This
  1360. is usefull in windowed applications for temporarily stopping rendering
  1361. (when moving the window, for example). *)
  1362. procedure Freeze;
  1363. { Restarts rendering after it was freezed. }
  1364. procedure Melt;
  1365. // Displays a window with info on current OpenGL ICD and context.
  1366. procedure ShowInfo(Modal: Boolean = False);
  1367. // Currently Rendering?
  1368. property Rendering: Boolean read FRendering;
  1369. // Adjusts background alpha channel.
  1370. property BackgroundAlpha: Single read FBackgroundAlpha write SetBackgroundAlpha;
  1371. // Returns the projection matrix in use or used for the last rendering.
  1372. function ProjectionMatrix: TMatrix4f; deprecated;
  1373. // Returns the view matrix in use or used for the last rendering.
  1374. function ViewMatrix: TMatrix4f; deprecated;
  1375. function ModelMatrix: TMatrix4f; deprecated;
  1376. (* Returns the base projection matrix in use or used for the last rendering.
  1377. The "base" projection is (as of now) either identity or the pick
  1378. matrix, ie. it is the matrix on which the perspective or orthogonal
  1379. matrix gets applied. *)
  1380. property BaseProjectionMatrix: TMatrix4f read FBaseProjectionMatrix;
  1381. (* Back up current View matrix and replace it with newMatrix.
  1382. This method has no effect on theOpenVX matrix, only on the Buffer's
  1383. matrix, and is intended for special effects rendering. *)
  1384. procedure PushViewMatrix(const newMatrix: TMatrix4f); deprecated;
  1385. // Restore a View matrix previously pushed.
  1386. procedure PopViewMatrix; deprecated;
  1387. procedure PushProjectionMatrix(const newMatrix: TMatrix4f); deprecated;
  1388. procedure PopProjectionMatrix; deprecated;
  1389. (* Converts a screen pixel coordinate into 3D coordinates for orthogonal projection.
  1390. This function accepts standard canvas coordinates, with (0,0) being
  1391. the top left corner, and returns, when the camera is in orthogonal
  1392. mode, the corresponding 3D world point that is in the camera's plane. *)
  1393. function OrthoScreenToWorld(screenX, screenY: Integer): TAffineVector; overload;
  1394. (* Converts a screen coordinate into world (3D) coordinates.
  1395. This methods wraps a call to gluUnProject.
  1396. Note that screen coord (0,0) is the lower left corner. *)
  1397. function ScreenToWorld(const aPoint: TAffineVector): TAffineVector; overload;
  1398. function ScreenToWorld(const aPoint: TVector4f): TVector4f; overload;
  1399. (* Converts a screen pixel coordinate into 3D world coordinates.
  1400. This function accepts standard canvas coordinates, with (0,0) being
  1401. the top left corner. *)
  1402. function ScreenToWorld(screenX, screenY: Integer): TAffineVector; overload;
  1403. (* Converts an absolute world coordinate into screen coordinate.
  1404. This methods wraps a call to gluProject.
  1405. Note that screen coord (0,0) is the lower left corner. *)
  1406. function WorldToScreen(const aPoint: TAffineVector): TAffineVector; overload;
  1407. function WorldToScreen(const aPoint: TVector4f): TVector4f; overload;
  1408. // Converts a set of point absolute world coordinates into screen coordinates.
  1409. procedure WorldToScreen(points: PVector4f; nbPoints: Integer); overload;
  1410. (* Calculates the 3D vector corresponding to a 2D screen coordinate.
  1411. The vector originates from the camera's absolute position and is
  1412. expressed in absolute coordinates.
  1413. Note that screen coord (0,0) is the lower left corner. *)
  1414. function ScreenToVector(const aPoint: TAffineVector): TAffineVector; overload;
  1415. function ScreenToVector(const aPoint: TVector4f): TVector4f; overload;
  1416. function ScreenToVector(const x, y: Integer): TVector4f; overload;
  1417. (* Calculates the 2D screen coordinate of a vector from the camera's
  1418. absolute position and is expressed in absolute coordinates.
  1419. Note that screen coord (0,0) is the lower left corner. *)
  1420. function VectorToScreen(const VectToCam: TAffineVector): TAffineVector;
  1421. (* Calculates intersection between a plane and screen vector.
  1422. If an intersection is found, returns True and places result in
  1423. intersectPoint. *)
  1424. function ScreenVectorIntersectWithPlane(const aScreenPoint: TVector4f; const planePoint, planeNormal: TVector4f;
  1425. var intersectPoint: TVector4f): Boolean;
  1426. (* Calculates intersection between plane XY and screen vector.
  1427. If an intersection is found, returns True and places result in intersectPoint. *)
  1428. function ScreenVectorIntersectWithPlaneXY(const aScreenPoint: TVector4f; const z: Single;
  1429. var intersectPoint: TVector4f): Boolean;
  1430. (* Calculates intersection between plane YZ and screen vector.
  1431. If an intersection is found, returns True and places result in intersectPoint. *)
  1432. function ScreenVectorIntersectWithPlaneYZ(const aScreenPoint: TVector4f; const x: Single;
  1433. var intersectPoint: TVector4f): Boolean;
  1434. (* Calculates intersection between plane XZ and screen vector.
  1435. If an intersection is found, returns True and places result in intersectPoint. *)
  1436. function ScreenVectorIntersectWithPlaneXZ(const aScreenPoint: TVector4f; const y: Single;
  1437. var intersectPoint: TVector4f): Boolean;
  1438. (* Calculates a 3D coordinate from screen position and ZBuffer.
  1439. This function returns a world absolute coordinate from a 2D point
  1440. in the viewer, the depth being extracted from the ZBuffer data
  1441. (DepthTesting and ZBuffer must be enabled for this function to work).
  1442. Note that ZBuffer precision is not linear and can be quite low on
  1443. some boards (either from compression or resolution approximations). *)
  1444. function PixelRayToWorld(x, y: Integer): TAffineVector;
  1445. (* Time (in second) spent to issue rendering order for the last frame.
  1446. Be aware that since execution by the hardware isn't synchronous,
  1447. this value may not be an accurate measurement of the time it took
  1448. to render the last frame, it's a measurement of only the time it
  1449. took to issue rendering orders. *)
  1450. property LastFrameTime: Single read FLastFrameTime;
  1451. (* Current FramesPerSecond rendering speed.
  1452. You must keep the renderer busy to get accurate figures from this
  1453. property.
  1454. This is an average value, to reset the counter, call
  1455. ResetPerfomanceMonitor. *)
  1456. property FramesPerSecond: Single read FFramesPerSecond;
  1457. (* Resets the perfomance monitor and begin a new statistics set.
  1458. See FramesPerSecond. *)
  1459. procedure ResetPerformanceMonitor;
  1460. (* Retrieve one of the OpenGL limits for the current viewer.
  1461. Limits include max texture size, OpenGL stack depth, etc. *)
  1462. property LimitOf[Which: TgxLimitType]: Integer read GetLimit;
  1463. (* Current rendering context.
  1464. The context is a wrapper around platform-specific contexts
  1465. (see TgxContext) and takes care of context activation and handle
  1466. management. *)
  1467. property RenderingContext: TgxContext read FRenderingContext;
  1468. (* The camera from which the scene is rendered.
  1469. A camera is an object you can add and define in a TgxScene component. *)
  1470. property Camera: TgxCamera read FCamera write SetCamera;
  1471. // Specifies the layer plane that the rendering context is bound to.
  1472. property Layer: TgxContextLayer read FLayer write SetLayer default clMainPlane;
  1473. published
  1474. // Fog environment options. See TgxFogEnvironment.
  1475. property FogEnvironment: TgxFogEnvironment read FFogEnvironment write SetFogEnvironment stored StoreFog;
  1476. // Color used for filling the background prior to any rendering.
  1477. property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor default TColors.SysBtnFace;
  1478. (* Scene ambient color vector.
  1479. This ambient color is defined independantly from all lightsources,
  1480. which can have their own ambient components. *)
  1481. property AmbientColor: TgxColor read FAmbientColor write SetAmbientColor;
  1482. (* Context options allows to setup specifics of the rendering context.
  1483. Not all contexts support all options. *)
  1484. property ContextOptions: TgxContextOptions read FContextOptions write SetContextOptions
  1485. default [roDoubleBuffer, roRenderToWindow, roDebugContext];
  1486. // Number of precision bits for the accumulation buffer.
  1487. property AccumBufferBits: Integer read FAccumBufferBits write SetAccumBufferBits default 0;
  1488. (* DepthTest enabling.
  1489. When DepthTest is enabled, objects closer to the camera will hide
  1490. farther ones (via use of Z-Buffering).
  1491. When DepthTest is disabled, the latest objects drawn/rendered overlap
  1492. all previous objects, whatever their distance to the camera.
  1493. Even when DepthTest is enabled, objects may chose to ignore depth
  1494. testing through the osIgnoreDepthBuffer of their ObjectStyle property. *)
  1495. property DepthTest: Boolean read FDepthTest write SetDepthTest default True;
  1496. (* Enable or disable face culling in the renderer.
  1497. Face culling is used in hidden faces removal algorithms : each face
  1498. is given a normal or 'outside' direction. When face culling is enabled,
  1499. only faces whose normal points towards the observer are rendered. *)
  1500. property FaceCulling: Boolean read FFaceCulling write SetFaceCulling default True;
  1501. // Toggle to enable or disable the fog settings.
  1502. property FogEnable: Boolean read FFogEnable write SetFogEnable default False;
  1503. (* Toggle to enable or disable lighting calculations.
  1504. When lighting is enabled, objects will be lit according to lightsources,
  1505. when lighting is disabled, objects are rendered in their own colors,
  1506. without any shading.
  1507. Lighting does NOT generate shadows in OpenGL. *)
  1508. property Lighting: Boolean read FLighting write SetLighting default True;
  1509. (* AntiAliasing option.
  1510. Ignored if not hardware supported, currently based on ARB_multisample. *)
  1511. property AntiAliasing: TgxAntiAliasing read FAntiAliasing write SetAntiAliasing default aaDefault;
  1512. (* Depth buffer precision.
  1513. Default is highest available (below and including 24 bits) *)
  1514. property DepthPrecision: TgxDepthPrecision read FDepthPrecision write SetDepthPrecision default dpDefault;
  1515. (* Color buffer depth.
  1516. Default depth buffer is highest available (below and including 24 bits) *)
  1517. property ColorDepth: TgxColorDepth read FColorDepth write SetColorDepth default cdDefault;
  1518. // Shade model. Default is "Smooth".
  1519. property ShadeModel: TgxShadeModel read FShadeModel write SetShadeModel default smDefault;
  1520. (* Indicates a change in the scene or buffer options.
  1521. A simple re-render is enough to take into account the changes. *)
  1522. property OnChange: TNotifyEvent read FOnChange write FOnChange stored False;
  1523. (* Indicates a structural change in the scene or buffer options.
  1524. A reconstruction of the RC is necessary to take into account the
  1525. changes (this may lead to a driver switch or lengthy operations). *)
  1526. property OnStructuralChange: TNotifyEvent read FOnStructuralChange write FOnStructuralChange stored False;
  1527. (* Triggered before the scene's objects get rendered.
  1528. You may use this event to execute your own OpenGL rendering
  1529. (usually background stuff). *)
  1530. property BeforeRender: TNotifyEvent read FBeforeRender write FBeforeRender stored False;
  1531. (* Triggered after BeforeRender, before rendering objects.
  1532. This one is fired after the rci has been initialized and can be used
  1533. to alter it or perform early renderings that require an rci,
  1534. the Sender is the buffer. *)
  1535. property InitiateRendering: TDirectRenderEvent read FInitiateRendering write FInitiateRendering stored False;
  1536. (* Triggered after rendering all scene objects, before PostRender.
  1537. This is the last point after which the rci becomes unavailable,
  1538. the Sender is the buffer. *)
  1539. property WrapUpRendering: TDirectRenderEvent read FWrapUpRendering write FWrapUpRendering stored False;
  1540. (* Triggered just after all the scene's objects have been rendered.
  1541. The OpenGL context is still active in this event, and you may use it
  1542. to execute your own OpenGL rendering (usually for HUD, 2D overlays
  1543. or after effects). *)
  1544. property PostRender: TNotifyEvent read FPostRender write FPostRender stored False;
  1545. (* Called after rendering.
  1546. You cannot issue OpenGL calls in this event, if you want to do your own
  1547. OpenGL stuff, use the PostRender event. *)
  1548. property AfterRender: TNotifyEvent read FAfterRender write FAfterRender stored False;
  1549. end;
  1550. (* Base class for non-visual viewer.
  1551. Non-visual viewer may actually render visuals, but they are non-visual
  1552. (ie. non interactive) at design time. Such viewers include memory
  1553. or full-screen viewers. *)
  1554. TgxNonVisualViewer = class(TComponent)
  1555. private
  1556. FBuffer: TgxSceneBuffer;
  1557. FWidth, FHeight: Integer;
  1558. FCubeMapRotIdx: Integer;
  1559. FCubeMapZNear, FCubeMapZFar: Single;
  1560. FCubeMapTranslation: TAffineVector;
  1561. // FCreateTexture : Boolean;
  1562. protected
  1563. procedure SetBeforeRender(const val: TNotifyEvent);
  1564. function GetBeforeRender: TNotifyEvent;
  1565. procedure SetPostRender(const val: TNotifyEvent);
  1566. function GetPostRender: TNotifyEvent;
  1567. procedure SetAfterRender(const val: TNotifyEvent);
  1568. function GetAfterRender: TNotifyEvent;
  1569. procedure SetCamera(const val: TgxCamera);
  1570. function GetCamera: TgxCamera;
  1571. procedure SetBuffer(const val: TgxSceneBuffer);
  1572. procedure SetWidth(const val: Integer);
  1573. procedure SetHeight(const val: Integer);
  1574. procedure SetupCubeMapCamera(Sender: TObject);
  1575. procedure DoOnPrepareVXContext(Sender: TObject);
  1576. procedure PrepareVXContext; virtual;
  1577. procedure DoBufferChange(Sender: TObject); virtual;
  1578. procedure DoBufferStructuralChange(Sender: TObject); virtual;
  1579. public
  1580. constructor Create(AOwner: TComponent); override;
  1581. destructor Destroy; override;
  1582. procedure Notification(AComponent: TComponent; Operation: TOperation); override;
  1583. procedure Render(baseObject: TgxBaseSceneObject = nil); virtual; abstract;
  1584. procedure CopyToTexture(aTexture: TgxTexture); overload; virtual;
  1585. procedure CopyToTexture(aTexture: TgxTexture; xSrc, ySrc, width, height: Integer; xDest, yDest: Integer); overload;
  1586. // CopyToTexture for Multiple-Render-Target
  1587. procedure CopyToTextureMRT(aTexture: TgxTexture; BufferIndex: Integer); overload; virtual;
  1588. procedure CopyToTextureMRT(aTexture: TgxTexture; xSrc, ySrc, width, height: Integer; xDest, yDest: Integer;
  1589. BufferIndex: Integer); overload;
  1590. (* Renders the 6 texture maps from a scene.
  1591. The viewer is used to render the 6 images, one for each face
  1592. of the cube, from the absolute position of the camera.
  1593. This does NOT alter the content of the Pictures in the image,
  1594. and will only change or define the content of textures as
  1595. registered by OpenGL. *)
  1596. procedure RenderCubeMapTextures(cubeMapTexture: TgxTexture; zNear: Single = 0; zFar: Single = 0);
  1597. published
  1598. // Camera from which the scene is rendered.
  1599. property Camera: TgxCamera read GetCamera write SetCamera;
  1600. property width: Integer read FWidth write SetWidth default 256;
  1601. property height: Integer read FHeight write SetHeight default 256;
  1602. (* Triggered before the scene's objects get rendered.
  1603. You may use this event to execute your own OpenGL rendering. *)
  1604. property BeforeRender: TNotifyEvent read GetBeforeRender write SetBeforeRender;
  1605. (* Triggered just after all the scene's objects have been rendered.
  1606. The OpenGL context is still active in this event, and you may use it
  1607. to execute your own OpenGL rendering. *)
  1608. property PostRender: TNotifyEvent read GetPostRender write SetPostRender;
  1609. (* Called after rendering.
  1610. You cannot issue OpenGL calls in this event, if you want to do your own
  1611. OpenGL stuff, use the PostRender event. *)
  1612. property AfterRender: TNotifyEvent read GetAfterRender write SetAfterRender;
  1613. // Access to buffer properties.
  1614. property Buffer: TgxSceneBuffer read FBuffer write SetBuffer;
  1615. end;
  1616. (* Component to render a scene to memory only.
  1617. This component curently requires that the OpenGL ICD supports the
  1618. WGL_ARB_pbuffer extension (indirectly). *)
  1619. TgxMemoryViewer = class(TgxNonVisualViewer)
  1620. private
  1621. FBufferCount: Integer;
  1622. procedure SetBufferCount(const Value: Integer);
  1623. public
  1624. constructor Create(AOwner: TComponent); override;
  1625. procedure InstantiateRenderingContext;
  1626. procedure Render(baseObject: TgxBaseSceneObject = nil); override;
  1627. published
  1628. (* Set BufferCount > 1 for multiple render targets.
  1629. Users should check if the corresponding extension (GL_ATI_draw_buffers)
  1630. is supported. Current hardware limit is BufferCount = 4. *)
  1631. property BufferCount: Integer read FBufferCount write SetBufferCount default 1;
  1632. end;
  1633. TInvokeInfoForm = procedure(aSceneBuffer: TgxSceneBuffer; Modal: Boolean);
  1634. (* Register an event handler triggered by any TgxBaseSceneObject Name change.
  1635. *INCOMPLETE*, currently allows for only 1 (one) event, and is used by
  1636. FSceneEdit in the IDE. *)
  1637. procedure RegisterBaseSceneObjectNameChangeEvent(notifyEvent: TNotifyEvent);
  1638. (* Deregister an event handler triggered by any TgxBaseSceneObject Name change.
  1639. See RegisterVKBaseSceneObjectNameChangeEvent. *)
  1640. procedure DeRegisterBaseSceneObjectNameChangeEvent(notifyEvent: TNotifyEvent);
  1641. (* Register an event handler triggered by any TgxBehaviour Name change.
  1642. *INCOMPLETE*, currently allows for only 1 (one) event, and is used by
  1643. FBehavioursEditor in the IDE. *)
  1644. procedure RegisterBehaviourNameChangeEvent(notifyEvent: TNotifyEvent);
  1645. (* Deregister an event handler triggered by any TgxBaseSceneObject Name change.
  1646. See RegisterVKBaseSceneObjectNameChangeEvent. *)
  1647. procedure DeRegisterBehaviourNameChangeEvent(notifyEvent: TNotifyEvent);
  1648. // Issues OpenGL calls for drawing X, Y, Z axes in a standard style.
  1649. procedure AxesBuildList(var rci: TgxRenderContextInfo; pattern: Word; AxisLen: Single);
  1650. // Registers the procedure call used to invoke the info form.
  1651. procedure RegisterInfoForm(infoForm: TInvokeInfoForm);
  1652. procedure InvokeInfoForm(aSceneBuffer: TgxSceneBuffer; Modal: Boolean);
  1653. function GetCurrentRenderingObject: TgxBaseSceneObject;
  1654. var
  1655. vCounterFrequency: Int64;
  1656. {$IFNDEF USE_MULTITHREAD}
  1657. var
  1658. {$ELSE}
  1659. threadvar
  1660. {$ENDIF}
  1661. vCurrentRenderingObject: TgxBaseSceneObject;
  1662. implementation // -----------------------------------------------------------
  1663. function GetCurrentRenderingObject: TgxBaseSceneObject;
  1664. begin
  1665. Result := vCurrentRenderingObject;
  1666. end;
  1667. procedure AxesBuildList(var rci: TgxRenderContextInfo; pattern: Word; AxisLen: Single);
  1668. begin
  1669. {$IFDEF USE_OPENGL_DEBUG}
  1670. if GL_GREMEDY_string_marker then
  1671. GL_StringMarkerGREMEDY(13, 'AxesBuildList');
  1672. {$ENDIF}
  1673. with rci.gxStates do
  1674. begin
  1675. Disable(stLighting);
  1676. if not rci.ignoreBlendingRequests then
  1677. begin
  1678. Enable(stBlend);
  1679. SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
  1680. end;
  1681. LineWidth := 1;
  1682. Enable(stLineStipple);
  1683. LineStippleFactor := 1;
  1684. LineStipplePattern := pattern;
  1685. DepthWriteMask := False;
  1686. DepthFunc := cfLEqual;
  1687. if rci.bufferDepthTest then
  1688. Enable(stDepthTest);
  1689. end;
  1690. glBegin(GL_LINES);
  1691. glColor3f(0.5, 0.0, 0.0);
  1692. glVertex3f(0, 0, 0);
  1693. glVertex3f(-AxisLen, 0, 0);
  1694. glColor3f(1.0, 0.0, 0.0);
  1695. glVertex3f(0, 0, 0);
  1696. glVertex3f(AxisLen, 0, 0);
  1697. glColor3f(0.0, 0.5, 0.0);
  1698. glVertex3f(0, 0, 0);
  1699. glVertex3f(0, -AxisLen, 0);
  1700. glColor3f(0.0, 1.0, 0.0);
  1701. glVertex3f(0, 0, 0);
  1702. glVertex3f(0, AxisLen, 0);
  1703. glColor3f(0.0, 0.0, 0.5);
  1704. glVertex3f(0, 0, 0);
  1705. glVertex3f(0, 0, -AxisLen);
  1706. glColor3f(0.0, 0.0, 1.0);
  1707. glVertex3f(0, 0, 0);
  1708. glVertex3f(0, 0, AxisLen);
  1709. glEnd;
  1710. end;
  1711. var
  1712. vInfoForm: TInvokeInfoForm = nil;
  1713. procedure RegisterInfoForm(infoForm: TInvokeInfoForm);
  1714. begin
  1715. vInfoForm := infoForm;
  1716. end;
  1717. procedure InvokeInfoForm(aSceneBuffer: TgxSceneBuffer; Modal: Boolean);
  1718. begin
  1719. if Assigned(vInfoForm) then
  1720. vInfoForm(aSceneBuffer, Modal)
  1721. else
  1722. InformationDlg('InfoForm not available.');
  1723. end;
  1724. // ------------------ internal global routines ----------------------------------
  1725. var
  1726. vBaseSceneObjectNameChangeEvent: TNotifyEvent;
  1727. vBehaviourNameChangeEvent: TNotifyEvent;
  1728. procedure RegisterBaseSceneObjectNameChangeEvent(notifyEvent: TNotifyEvent);
  1729. begin
  1730. vBaseSceneObjectNameChangeEvent := notifyEvent;
  1731. end;
  1732. procedure DeRegisterBaseSceneObjectNameChangeEvent(notifyEvent: TNotifyEvent);
  1733. begin
  1734. vBaseSceneObjectNameChangeEvent := nil;
  1735. end;
  1736. procedure RegisterBehaviourNameChangeEvent(notifyEvent: TNotifyEvent);
  1737. begin
  1738. vBehaviourNameChangeEvent := notifyEvent;
  1739. end;
  1740. procedure DeRegisterBehaviourNameChangeEvent(notifyEvent: TNotifyEvent);
  1741. begin
  1742. vBehaviourNameChangeEvent := nil;
  1743. end;
  1744. // ------------------
  1745. // ------------------ TgxBaseSceneObject ------------------
  1746. // ------------------
  1747. constructor TgxBaseSceneObject.Create(AOwner: TComponent);
  1748. begin
  1749. inherited Create(AOwner);
  1750. FListHandle := TgxListHandle.Create;
  1751. FObjectStyle := [];
  1752. FChanges := [ocTransformation, ocStructure, ocAbsoluteMatrix, ocInvAbsoluteMatrix];
  1753. FPosition := TgxCoordinates.CreateInitialized(Self, NullHmgPoint, csPoint);
  1754. FRotation := TgxCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
  1755. FDirection := TgxCoordinates.CreateInitialized(Self, ZHmgVector, csVector);
  1756. FUp := TgxCoordinates.CreateInitialized(Self, YHmgVector, csVector);
  1757. FScaling := TgxCoordinates.CreateInitialized(Self, XYZHmgVector, csVector);
  1758. FLocalMatrix := IdentityHmgMatrix;
  1759. FVisible := True;
  1760. FPickable := True;
  1761. FObjectsSorting := osInherited;
  1762. FVisibilityCulling := vcInherited;
  1763. FChildren := TgxPersistentObjectList.Create;
  1764. FBBChanges := [oBBcChild, oBBcStructure];
  1765. FBoundingBoxPersonalUnscaled := NullBoundingBox;
  1766. FBoundingBoxOfChildren := NullBoundingBox;
  1767. FBoundingBoxIncludingChildren := NullBoundingBox;
  1768. distList := TgxSingleList.Create;
  1769. objList := TgxPersistentObjectList.Create;
  1770. end;
  1771. constructor TgxBaseSceneObject.CreateAsChild(aParentOwner: TgxBaseSceneObject);
  1772. begin
  1773. Create(aParentOwner);
  1774. aParentOwner.AddChild(Self);
  1775. end;
  1776. destructor TgxBaseSceneObject.Destroy;
  1777. begin
  1778. DeleteChildCameras;
  1779. FEffects.Free;
  1780. FBehaviours.Free;
  1781. FListHandle.Free;
  1782. FPosition.Free;
  1783. FRotation.Free;
  1784. FDirection.Free;
  1785. FUp.Free;
  1786. FScaling.Free;
  1787. if Assigned(FParent) then
  1788. FParent.Remove(Self, False);
  1789. DeleteChildren;
  1790. FChildren.Free;
  1791. objList.Free;
  1792. distList.Free;
  1793. inherited Destroy;
  1794. end;
  1795. function TgxBaseSceneObject.GetHandle(var rci: TgxRenderContextInfo): Cardinal;
  1796. begin
  1797. // Special case.. dirty trixxors
  1798. if not Assigned(FListHandle) then
  1799. begin
  1800. Result := 0;
  1801. Exit;
  1802. end;
  1803. Result := FListHandle.Handle;
  1804. if Result = 0 then
  1805. Result := FListHandle.AllocateHandle;
  1806. if ocStructure in FChanges then
  1807. begin
  1808. ClearStructureChanged;
  1809. FListHandle.NotifyChangesOfData;
  1810. end;
  1811. if FListHandle.IsDataNeedUpdate then
  1812. begin
  1813. rci.gxStates.NewList(Result, GL_COMPILE);
  1814. // try
  1815. BuildList(rci);
  1816. // finally
  1817. rci.gxStates.EndList;
  1818. // end;
  1819. FListHandle.NotifyDataUpdated;
  1820. end;
  1821. end;
  1822. function TgxBaseSceneObject.ListHandleAllocated: Boolean;
  1823. begin
  1824. Result := Assigned(FListHandle) and (FListHandle.Handle <> 0) and not(ocStructure in FChanges);
  1825. end;
  1826. procedure TgxBaseSceneObject.DestroyHandle;
  1827. begin
  1828. if Assigned(FListHandle) then
  1829. FListHandle.DestroyHandle;
  1830. end;
  1831. procedure TgxBaseSceneObject.DestroyHandles;
  1832. var
  1833. i: Integer;
  1834. begin
  1835. for i := 0 to Count - 1 do
  1836. Children[i].DestroyHandles;
  1837. DestroyHandle;
  1838. end;
  1839. procedure TgxBaseSceneObject.SetBBChanges(const Value: TgxObjectBBChanges);
  1840. begin
  1841. if Value <> FBBChanges then
  1842. begin
  1843. FBBChanges := Value;
  1844. if Assigned(FParent) then
  1845. FParent.BBChanges := FParent.BBChanges + [oBBcChild];
  1846. end;
  1847. end;
  1848. function TgxBaseSceneObject.Blended: Boolean;
  1849. begin
  1850. Result := False;
  1851. end;
  1852. procedure TgxBaseSceneObject.BeginUpdate;
  1853. begin
  1854. Inc(FUpdateCount);
  1855. end;
  1856. procedure TgxBaseSceneObject.EndUpdate;
  1857. begin
  1858. if FUpdateCount > 0 then
  1859. begin
  1860. Dec(FUpdateCount);
  1861. if FUpdateCount = 0 then
  1862. NotifyChange(Self);
  1863. end
  1864. else
  1865. Assert(False, strUnBalancedBeginEndUpdate);
  1866. end;
  1867. procedure TgxBaseSceneObject.BuildList(var rci: TgxRenderContextInfo);
  1868. begin
  1869. // nothing
  1870. end;
  1871. procedure TgxBaseSceneObject.DeleteChildCameras;
  1872. var
  1873. i: Integer;
  1874. child: TgxBaseSceneObject;
  1875. begin
  1876. i := 0;
  1877. while i < FChildren.Count do
  1878. begin
  1879. child := TgxBaseSceneObject(FChildren.List^[i]);
  1880. child.DeleteChildCameras;
  1881. if child is TgxCamera then
  1882. begin
  1883. Remove(child, True);
  1884. child.Free;
  1885. end
  1886. else
  1887. Inc(i);
  1888. end;
  1889. end;
  1890. procedure TgxBaseSceneObject.DeleteChildren;
  1891. var
  1892. child: TgxBaseSceneObject;
  1893. begin
  1894. DeleteChildCameras;
  1895. if Assigned(FScene) then
  1896. FScene.RemoveLights(Self);
  1897. while FChildren.Count > 0 do
  1898. begin
  1899. child := TgxBaseSceneObject(FChildren.Pop);
  1900. child.FParent := nil;
  1901. child.Free;
  1902. end;
  1903. BBChanges := BBChanges + [oBBcChild];
  1904. end;
  1905. procedure TgxBaseSceneObject.Loaded;
  1906. begin
  1907. inherited;
  1908. FPosition.W := 1;
  1909. if Assigned(FBehaviours) then
  1910. FBehaviours.Loaded;
  1911. if Assigned(FEffects) then
  1912. FEffects.Loaded;
  1913. end;
  1914. procedure TgxBaseSceneObject.DefineProperties(Filer: TFiler);
  1915. begin
  1916. inherited;
  1917. { FOriginalFiler := Filer; }
  1918. Filer.DefineBinaryProperty('BehavioursData', ReadBehaviours, WriteBehaviours,
  1919. (Assigned(FBehaviours) and (FBehaviours.Count > 0)));
  1920. Filer.DefineBinaryProperty('EffectsData', ReadEffects, WriteEffects,
  1921. (Assigned(FEffects) and (FEffects.Count > 0)));
  1922. { FOriginalFiler:=nil; }
  1923. end;
  1924. procedure TgxBaseSceneObject.WriteBehaviours(stream: TStream);
  1925. var
  1926. writer: TWriter;
  1927. begin
  1928. writer := TWriter.Create(stream, 16384);
  1929. try
  1930. Behaviours.WriteToFiler(writer);
  1931. finally
  1932. writer.Free;
  1933. end;
  1934. end;
  1935. procedure TgxBaseSceneObject.ReadBehaviours(stream: TStream);
  1936. var
  1937. reader: TReader;
  1938. begin
  1939. reader := TReader.Create(stream, 16384);
  1940. { with TReader(FOriginalFiler) do }
  1941. try
  1942. { reader.Root := Root;
  1943. reader.OnError := OnError;
  1944. reader.OnFindMethod := OnFindMethod;
  1945. reader.OnSetName := OnSetName;
  1946. reader.OnReferenceName := OnReferenceName;
  1947. reader.OnAncestorNotFound := OnAncestorNotFound;
  1948. reader.OnCreateComponent := OnCreateComponent;
  1949. reader.OnFindComponentClass := OnFindComponentClass; }
  1950. Behaviours.ReadFromFiler(reader);
  1951. finally
  1952. reader.Free;
  1953. end;
  1954. end;
  1955. procedure TgxBaseSceneObject.WriteEffects(stream: TStream);
  1956. var
  1957. writer: TWriter;
  1958. begin
  1959. writer := TWriter.Create(stream, 16384);
  1960. try
  1961. Effects.WriteToFiler(writer);
  1962. finally
  1963. writer.Free;
  1964. end;
  1965. end;
  1966. procedure TgxBaseSceneObject.ReadEffects(stream: TStream);
  1967. var
  1968. reader: TReader;
  1969. begin
  1970. reader := TReader.Create(stream, 16384);
  1971. // with TReader(FOriginalFiler) do
  1972. try
  1973. (* reader.Root := Root;
  1974. reader.OnError := OnError;
  1975. reader.OnFindMethod := OnFindMethod;
  1976. reader.OnSetName := OnSetName;
  1977. reader.OnReferenceName := OnReferenceName;
  1978. reader.OnAncestorNotFound := OnAncestorNotFound;
  1979. reader.OnCreateComponent := OnCreateComponent;
  1980. reader.OnFindComponentClass := OnFindComponentClass; *)
  1981. Effects.ReadFromFiler(reader);
  1982. finally
  1983. reader.Free;
  1984. end;
  1985. end;
  1986. procedure TgxBaseSceneObject.WriteRotations(stream: TStream);
  1987. begin
  1988. stream.Write(FRotation.AsAddress^, 3 * SizeOf(Single));
  1989. end;
  1990. procedure TgxBaseSceneObject.ReadRotations(stream: TStream);
  1991. begin
  1992. stream.Read(FRotation.AsAddress^, 3 * SizeOf(Single));
  1993. end;
  1994. procedure TgxBaseSceneObject.DrawAxes(var rci: TgxRenderContextInfo; pattern: Word);
  1995. begin
  1996. AxesBuildList(rci, pattern, rci.rcci.farClippingDistance - rci.rcci.nearClippingDistance);
  1997. end;
  1998. procedure TgxBaseSceneObject.GetChildren(AProc: TGetChildProc; Root: TComponent);
  1999. var
  2000. i: Integer;
  2001. begin
  2002. for i := 0 to FChildren.Count - 1 do
  2003. if not IsSubComponent(TComponent(FChildren.List^[i])) then
  2004. AProc(TComponent(FChildren.List^[i]));
  2005. end;
  2006. function TgxBaseSceneObject.Get(Index: Integer): TgxBaseSceneObject;
  2007. begin
  2008. Result := TgxBaseSceneObject(FChildren[Index]);
  2009. end;
  2010. function TgxBaseSceneObject.GetCount: Integer;
  2011. begin
  2012. Result := FChildren.Count;
  2013. end;
  2014. function TgxBaseSceneObject.GetDirectAbsoluteMatrix: PMatrix4f;
  2015. begin
  2016. Result := @FAbsoluteMatrix;
  2017. end;
  2018. function TgxBaseSceneObject.HasSubChildren: Boolean;
  2019. var
  2020. i: Integer;
  2021. begin
  2022. Result := False;
  2023. if Count <> 0 then
  2024. for i := 0 to Count - 1 do
  2025. if IsSubComponent(Children[i]) then
  2026. begin
  2027. Result := True;
  2028. Exit;
  2029. end;
  2030. end;
  2031. procedure TgxBaseSceneObject.AddChild(AChild: TgxBaseSceneObject);
  2032. begin
  2033. if Assigned(FScene) then
  2034. FScene.AddLights(AChild);
  2035. FChildren.Add(AChild);
  2036. AChild.FParent := Self;
  2037. AChild.SetScene(FScene);
  2038. TransformationChanged;
  2039. AChild.TransformationChanged;
  2040. AChild.DoOnAddedToParent;
  2041. BBChanges := BBChanges + [oBBcChild];
  2042. end;
  2043. function TgxBaseSceneObject.AddNewChild(AChild: TgxSceneObjectClass): TgxBaseSceneObject;
  2044. begin
  2045. Result := AChild.Create(Owner);
  2046. AddChild(Result);
  2047. end;
  2048. function TgxBaseSceneObject.AddNewChildFirst(AChild: TgxSceneObjectClass): TgxBaseSceneObject;
  2049. begin
  2050. Result := AChild.Create(Owner);
  2051. Insert(0, Result);
  2052. end;
  2053. function TgxBaseSceneObject.GetOrCreateBehaviour(aBehaviour: TgxBehaviourClass): TgxBehaviour;
  2054. begin
  2055. Result := TgxBehaviour(Behaviours.GetOrCreate(aBehaviour));
  2056. end;
  2057. function TgxBaseSceneObject.AddNewBehaviour(aBehaviour: TgxBehaviourClass): TgxBehaviour;
  2058. begin
  2059. Assert(Behaviours.CanAdd(aBehaviour));
  2060. Result := aBehaviour.Create(Behaviours)
  2061. end;
  2062. function TgxBaseSceneObject.GetOrCreateEffect(anEffect: TgxEffectClass): TgxEffect;
  2063. begin
  2064. Result := TgxEffect(Effects.GetOrCreate(anEffect));
  2065. end;
  2066. function TgxBaseSceneObject.AddNewEffect(anEffect: TgxEffectClass): TgxEffect;
  2067. begin
  2068. Assert(Effects.CanAdd(anEffect));
  2069. Result := anEffect.Create(Effects)
  2070. end;
  2071. procedure TgxBaseSceneObject.RebuildMatrix;
  2072. begin
  2073. if ocTransformation in Changes then
  2074. begin
  2075. VectorScale(LeftVector, Scale.x, FLocalMatrix.x);
  2076. VectorScale(FUp.AsVector, Scale.y, FLocalMatrix.y);
  2077. VectorScale(FDirection.AsVector, Scale.z, FLocalMatrix.z);
  2078. SetVector(FLocalMatrix.W, FPosition.AsVector);
  2079. Exclude(FChanges, ocTransformation);
  2080. Include(FChanges, ocAbsoluteMatrix);
  2081. Include(FChanges, ocInvAbsoluteMatrix);
  2082. end;
  2083. end;
  2084. procedure TgxBaseSceneObject.ForceLocalMatrix(const aMatrix: TMatrix4f);
  2085. begin
  2086. FLocalMatrix := aMatrix;
  2087. Exclude(FChanges, ocTransformation);
  2088. Include(FChanges, ocAbsoluteMatrix);
  2089. Include(FChanges, ocInvAbsoluteMatrix);
  2090. end;
  2091. function TgxBaseSceneObject.AbsoluteMatrixAsAddress: PMatrix4f;
  2092. begin
  2093. if ocAbsoluteMatrix in FChanges then
  2094. begin
  2095. RebuildMatrix;
  2096. if Assigned(Parent) { and (not (Parent is TgxSceneRootObject)) } then
  2097. begin
  2098. MatrixMultiply(FLocalMatrix, TgxBaseSceneObject(Parent).AbsoluteMatrixAsAddress^, FAbsoluteMatrix);
  2099. end
  2100. else
  2101. FAbsoluteMatrix := FLocalMatrix;
  2102. Exclude(FChanges, ocAbsoluteMatrix);
  2103. Include(FChanges, ocInvAbsoluteMatrix);
  2104. end;
  2105. Result := @FAbsoluteMatrix;
  2106. end;
  2107. function TgxBaseSceneObject.InvAbsoluteMatrix: TMatrix4f;
  2108. begin
  2109. Result := InvAbsoluteMatrixAsAddress^;
  2110. end;
  2111. function TgxBaseSceneObject.InvAbsoluteMatrixAsAddress: PMatrix4f;
  2112. begin
  2113. if ocInvAbsoluteMatrix in FChanges then
  2114. begin
  2115. if VectorEquals(Scale.DirectVector, XYZHmgVector) then
  2116. begin
  2117. RebuildMatrix;
  2118. if Parent <> nil then
  2119. FInvAbsoluteMatrix := MatrixMultiply(Parent.InvAbsoluteMatrixAsAddress^, AnglePreservingMatrixInvert(FLocalMatrix))
  2120. else
  2121. FInvAbsoluteMatrix := AnglePreservingMatrixInvert(FLocalMatrix);
  2122. end
  2123. else
  2124. begin
  2125. FInvAbsoluteMatrix := AbsoluteMatrixAsAddress^;
  2126. InvertMatrix(FInvAbsoluteMatrix);
  2127. end;
  2128. Exclude(FChanges, ocInvAbsoluteMatrix);
  2129. end;
  2130. Result := @FInvAbsoluteMatrix;
  2131. end;
  2132. function TgxBaseSceneObject.GetAbsoluteMatrix: TMatrix4f;
  2133. begin
  2134. Result := AbsoluteMatrixAsAddress^;
  2135. end;
  2136. procedure TgxBaseSceneObject.SetAbsoluteMatrix(const Value: TMatrix4f);
  2137. begin
  2138. if not MatrixEquals(Value, FAbsoluteMatrix) then
  2139. begin
  2140. FAbsoluteMatrix := Value;
  2141. if Parent <> nil then
  2142. SetMatrix(MatrixMultiply(FAbsoluteMatrix, Parent.InvAbsoluteMatrixAsAddress^))
  2143. else
  2144. SetMatrix(Value);
  2145. end;
  2146. end;
  2147. function TgxBaseSceneObject.GetAbsoluteDirection: TVector4f;
  2148. begin
  2149. Result := VectorNormalize(AbsoluteMatrixAsAddress^.z);
  2150. end;
  2151. procedure TgxBaseSceneObject.SetAbsoluteDirection(const v: TVector4f);
  2152. begin
  2153. if Parent <> nil then
  2154. Direction.AsVector := Parent.AbsoluteToLocal(v)
  2155. else
  2156. Direction.AsVector := v;
  2157. end;
  2158. function TgxBaseSceneObject.GetAbsoluteScale: TVector4f;
  2159. begin
  2160. Result.x := AbsoluteMatrixAsAddress^.x.x;
  2161. Result.y := AbsoluteMatrixAsAddress^.y.y;
  2162. Result.z := AbsoluteMatrixAsAddress^.z.z;
  2163. Result.W := 0;
  2164. end;
  2165. procedure TgxBaseSceneObject.SetAbsoluteScale(const Value: TVector4f);
  2166. begin
  2167. if Parent <> nil then
  2168. Scale.AsVector := Parent.AbsoluteToLocal(Value)
  2169. else
  2170. Scale.AsVector := Value;
  2171. end;
  2172. function TgxBaseSceneObject.GetAbsoluteUp: TVector4f;
  2173. begin
  2174. Result := VectorNormalize(AbsoluteMatrixAsAddress^.y);
  2175. end;
  2176. procedure TgxBaseSceneObject.SetAbsoluteUp(const v: TVector4f);
  2177. begin
  2178. if Parent <> nil then
  2179. Up.AsVector := Parent.AbsoluteToLocal(v)
  2180. else
  2181. Up.AsVector := v;
  2182. end;
  2183. function TgxBaseSceneObject.AbsoluteRight: TVector4f;
  2184. begin
  2185. Result := VectorNormalize(AbsoluteMatrixAsAddress^.x);
  2186. end;
  2187. function TgxBaseSceneObject.AbsoluteLeft: TVector4f;
  2188. begin
  2189. Result := VectorNegate(AbsoluteRight);
  2190. end;
  2191. function TgxBaseSceneObject.GetAbsolutePosition: TVector4f;
  2192. begin
  2193. Result := AbsoluteMatrixAsAddress^.W;
  2194. end;
  2195. procedure TgxBaseSceneObject.SetAbsolutePosition(const v: TVector4f);
  2196. begin
  2197. if Assigned(Parent) then
  2198. Position.AsVector := Parent.AbsoluteToLocal(v)
  2199. else
  2200. Position.AsVector := v;
  2201. end;
  2202. function TgxBaseSceneObject.AbsolutePositionAsAddress: PVector4f;
  2203. begin
  2204. Result := @AbsoluteMatrixAsAddress^.W;
  2205. end;
  2206. function TgxBaseSceneObject.AbsoluteXVector: TVector4f;
  2207. begin
  2208. AbsoluteMatrixAsAddress;
  2209. SetVector(Result, PAffineVector(@FAbsoluteMatrix.x)^);
  2210. end;
  2211. function TgxBaseSceneObject.AbsoluteYVector: TVector4f;
  2212. begin
  2213. AbsoluteMatrixAsAddress;
  2214. SetVector(Result, PAffineVector(@FAbsoluteMatrix.y)^);
  2215. end;
  2216. function TgxBaseSceneObject.AbsoluteZVector: TVector4f;
  2217. begin
  2218. AbsoluteMatrixAsAddress;
  2219. SetVector(Result, PAffineVector(@FAbsoluteMatrix.z)^);
  2220. end;
  2221. function TgxBaseSceneObject.AbsoluteToLocal(const v: TVector4f): TVector4f;
  2222. begin
  2223. Result := VectorTransform(v, InvAbsoluteMatrixAsAddress^);
  2224. end;
  2225. function TgxBaseSceneObject.AbsoluteToLocal(const v: TAffineVector): TAffineVector;
  2226. begin
  2227. Result := VectorTransform(v, InvAbsoluteMatrixAsAddress^);
  2228. end;
  2229. function TgxBaseSceneObject.LocalToAbsolute(const v: TVector4f): TVector4f;
  2230. begin
  2231. Result := VectorTransform(v, AbsoluteMatrixAsAddress^);
  2232. end;
  2233. function TgxBaseSceneObject.LocalToAbsolute(const v: TAffineVector): TAffineVector;
  2234. begin
  2235. Result := VectorTransform(v, AbsoluteMatrixAsAddress^);
  2236. end;
  2237. function TgxBaseSceneObject.Right: TVector4f;
  2238. begin
  2239. Result := VectorCrossProduct(FDirection.AsVector, FUp.AsVector);
  2240. end;
  2241. function TgxBaseSceneObject.LeftVector: TVector4f;
  2242. begin
  2243. Result := VectorCrossProduct(FUp.AsVector, FDirection.AsVector);
  2244. end;
  2245. function TgxBaseSceneObject.BarycenterAbsolutePosition: TVector4f;
  2246. begin
  2247. Result := AbsolutePosition;
  2248. end;
  2249. function TgxBaseSceneObject.SqrDistanceTo(anObject: TgxBaseSceneObject): Single;
  2250. begin
  2251. if Assigned(anObject) then
  2252. Result := VectorDistance2(AbsolutePosition, anObject.AbsolutePosition)
  2253. else
  2254. Result := 0;
  2255. end;
  2256. function TgxBaseSceneObject.SqrDistanceTo(const pt: TVector4f): Single;
  2257. begin
  2258. Result := VectorDistance2(pt, AbsolutePosition);
  2259. end;
  2260. function TgxBaseSceneObject.DistanceTo(anObject: TgxBaseSceneObject): Single;
  2261. begin
  2262. if Assigned(anObject) then
  2263. Result := VectorDistance(AbsolutePosition, anObject.AbsolutePosition)
  2264. else
  2265. Result := 0;
  2266. end;
  2267. function TgxBaseSceneObject.DistanceTo(const pt: TVector4f): Single;
  2268. begin
  2269. Result := VectorDistance(AbsolutePosition, pt);
  2270. end;
  2271. function TgxBaseSceneObject.BarycenterSqrDistanceTo(const pt: TVector4f): Single;
  2272. var
  2273. d: TVector4f;
  2274. begin
  2275. d := BarycenterAbsolutePosition;
  2276. Result := VectorDistance2(d, pt);
  2277. end;
  2278. function TgxBaseSceneObject.AxisAlignedDimensions: TVector4f;
  2279. begin
  2280. Result := AxisAlignedDimensionsUnscaled();
  2281. ScaleVector(Result, Scale.AsVector);
  2282. end;
  2283. function TgxBaseSceneObject.AxisAlignedDimensionsUnscaled: TVector4f;
  2284. begin
  2285. Result.x := 0.5;
  2286. Result.y := 0.5;
  2287. Result.z := 0.5;
  2288. Result.W := 0;
  2289. end;
  2290. function TgxBaseSceneObject.AxisAlignedBoundingBox(const AIncludeChilden: Boolean): TAABB;
  2291. var
  2292. i: Integer;
  2293. aabb: TAABB;
  2294. child: TgxBaseSceneObject;
  2295. begin
  2296. SetAABB(Result, AxisAlignedDimensionsUnscaled);
  2297. // not tested for child objects
  2298. if AIncludeChilden then
  2299. begin
  2300. for i := 0 to FChildren.Count - 1 do
  2301. begin
  2302. child := TgxBaseSceneObject(FChildren.List^[i]);
  2303. aabb := child.AxisAlignedBoundingBoxUnscaled(AIncludeChilden);
  2304. AABBTransform(aabb, child.Matrix^);
  2305. AddAABB(Result, aabb);
  2306. end;
  2307. end;
  2308. AABBScale(Result, Scale.AsAffineVector);
  2309. end;
  2310. function TgxBaseSceneObject.AxisAlignedBoundingBoxUnscaled(const AIncludeChilden: Boolean): TAABB;
  2311. var
  2312. i: Integer;
  2313. aabb: TAABB;
  2314. begin
  2315. SetAABB(Result, AxisAlignedDimensionsUnscaled);
  2316. // not tested for child objects
  2317. if AIncludeChilden then
  2318. begin
  2319. for i := 0 to FChildren.Count - 1 do
  2320. begin
  2321. aabb := TgxBaseSceneObject(FChildren.List^[i]).AxisAlignedBoundingBoxUnscaled(AIncludeChilden);
  2322. AABBTransform(aabb, TgxBaseSceneObject(FChildren.List^[i]).Matrix^);
  2323. AddAABB(Result, aabb);
  2324. end;
  2325. end;
  2326. end;
  2327. function TgxBaseSceneObject.AxisAlignedBoundingBoxAbsolute(const AIncludeChilden: Boolean;
  2328. const AUseBaryCenter: Boolean): TAABB;
  2329. begin
  2330. Result := BBToAABB(BoundingBoxAbsolute(AIncludeChilden, AUseBaryCenter));
  2331. end;
  2332. function TgxBaseSceneObject.BoundingBox(const AIncludeChilden: Boolean; const AUseBaryCenter: Boolean): THmgBoundingBox;
  2333. var
  2334. CurrentBaryOffset: TVector4f;
  2335. begin
  2336. Result := AABBToBB(AxisAlignedBoundingBox(AIncludeChilden));
  2337. // DaStr: code not tested...
  2338. if AUseBaryCenter then
  2339. begin
  2340. CurrentBaryOffset := VectorSubtract(AbsoluteToLocal(BarycenterAbsolutePosition), Position.AsVector);
  2341. OffsetBBPoint(Result, CurrentBaryOffset);
  2342. end;
  2343. end;
  2344. function TgxBaseSceneObject.BoundingBoxUnscaled(const AIncludeChilden: Boolean; const AUseBaryCenter: Boolean): THmgBoundingBox;
  2345. var
  2346. CurrentBaryOffset: TVector4f;
  2347. begin
  2348. Result := AABBToBB(AxisAlignedBoundingBoxUnscaled(AIncludeChilden));
  2349. // DaStr: code not tested...
  2350. if AUseBaryCenter then
  2351. begin
  2352. CurrentBaryOffset := VectorSubtract(AbsoluteToLocal(BarycenterAbsolutePosition), Position.AsVector);
  2353. OffsetBBPoint(Result, CurrentBaryOffset);
  2354. end;
  2355. end;
  2356. function TgxBaseSceneObject.BoundingBoxAbsolute(const AIncludeChilden: Boolean; const AUseBaryCenter: Boolean): THmgBoundingBox;
  2357. var
  2358. i: Integer;
  2359. CurrentBaryOffset: TVector4f;
  2360. begin
  2361. Result := BoundingBoxUnscaled(AIncludeChilden, False);
  2362. for i := 0 to 7 do
  2363. Result.BBox[i] := LocalToAbsolute(Result.BBox[i]);
  2364. if AUseBaryCenter then
  2365. begin
  2366. CurrentBaryOffset := VectorSubtract(BarycenterAbsolutePosition, AbsolutePosition);
  2367. OffsetBBPoint(Result, CurrentBaryOffset);
  2368. end;
  2369. end;
  2370. function TgxBaseSceneObject.BoundingSphereRadius: Single;
  2371. begin
  2372. Result := VectorLength(AxisAlignedDimensions);
  2373. end;
  2374. function TgxBaseSceneObject.BoundingSphereRadiusUnscaled: Single;
  2375. begin
  2376. Result := VectorLength(AxisAlignedDimensionsUnscaled);
  2377. end;
  2378. function TgxBaseSceneObject.PointInObject(const point: TVector4f): Boolean;
  2379. var
  2380. localPt, dim: TVector4f;
  2381. begin
  2382. dim := AxisAlignedDimensions;
  2383. localPt := VectorTransform(point, InvAbsoluteMatrix);
  2384. Result := (Abs(localPt.x * Scale.x) <= dim.x) and (Abs(localPt.y * Scale.y) <= dim.y) and (Abs(localPt.z * Scale.z) <= dim.z);
  2385. end;
  2386. procedure TgxBaseSceneObject.CalculateBoundingBoxPersonalUnscaled(var ANewBoundingBox: THmgBoundingBox);
  2387. begin
  2388. // Using the standard method to get the local BB.
  2389. ANewBoundingBox := AABBToBB(AxisAlignedBoundingBoxUnscaled(False));
  2390. OffsetBBPoint(ANewBoundingBox, AbsoluteToLocal(BarycenterAbsolutePosition));
  2391. end;
  2392. function TgxBaseSceneObject.BoundingBoxPersonalUnscaledEx: THmgBoundingBox;
  2393. begin
  2394. if oBBcStructure in FBBChanges then
  2395. begin
  2396. CalculateBoundingBoxPersonalUnscaled(FBoundingBoxPersonalUnscaled);
  2397. Exclude(FBBChanges, oBBcStructure);
  2398. end;
  2399. Result := FBoundingBoxPersonalUnscaled;
  2400. end;
  2401. function TgxBaseSceneObject.AxisAlignedBoundingBoxAbsoluteEx: TAABB;
  2402. var
  2403. pBB: THmgBoundingBox;
  2404. begin
  2405. pBB := BoundingBoxIncludingChildrenEx;
  2406. BBTransform(pBB, AbsoluteMatrix);
  2407. Result := BBToAABB(pBB);
  2408. end;
  2409. function TgxBaseSceneObject.AxisAlignedBoundingBoxEx: TAABB;
  2410. begin
  2411. Result := BBToAABB(BoundingBoxIncludingChildrenEx);
  2412. AABBScale(Result, Scale.AsAffineVector);
  2413. end;
  2414. function TgxBaseSceneObject.BoundingBoxOfChildrenEx: THmgBoundingBox;
  2415. var
  2416. i: Integer;
  2417. pBB: THmgBoundingBox;
  2418. begin
  2419. if oBBcChild in FBBChanges then
  2420. begin
  2421. // Computing
  2422. FBoundingBoxOfChildren := NullBoundingBox;
  2423. for i := 0 to FChildren.Count - 1 do
  2424. begin
  2425. pBB := TgxBaseSceneObject(FChildren.List^[i]).BoundingBoxIncludingChildrenEx;
  2426. if not BoundingBoxesAreEqual(@pBB, @NullBoundingBox) then
  2427. begin
  2428. // transformation with local matrix
  2429. BBTransform(pBB, TgxBaseSceneObject(FChildren.List^[i]).Matrix^);
  2430. if BoundingBoxesAreEqual(@FBoundingBoxOfChildren, @NullBoundingBox) then
  2431. FBoundingBoxOfChildren := pBB
  2432. else
  2433. AddBB(FBoundingBoxOfChildren, pBB);
  2434. end;
  2435. end;
  2436. Exclude(FBBChanges, oBBcChild);
  2437. end;
  2438. Result := FBoundingBoxOfChildren;
  2439. end;
  2440. function TgxBaseSceneObject.BoundingBoxIncludingChildrenEx: THmgBoundingBox;
  2441. var
  2442. pBB: THmgBoundingBox;
  2443. begin
  2444. if (oBBcStructure in FBBChanges) or (oBBcChild in FBBChanges) then
  2445. begin
  2446. pBB := BoundingBoxPersonalUnscaledEx;
  2447. if BoundingBoxesAreEqual(@pBB, @NullBoundingBox) then
  2448. FBoundingBoxIncludingChildren := BoundingBoxOfChildrenEx
  2449. else
  2450. begin
  2451. FBoundingBoxIncludingChildren := pBB;
  2452. pBB := BoundingBoxOfChildrenEx;
  2453. if not BoundingBoxesAreEqual(@pBB, @NullBoundingBox) then
  2454. AddBB(FBoundingBoxIncludingChildren, pBB);
  2455. end;
  2456. end;
  2457. Result := FBoundingBoxIncludingChildren;
  2458. end;
  2459. function TgxBaseSceneObject.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
  2460. intersectNormal: PVector4f = nil): Boolean;
  2461. var
  2462. i1, i2, absPos: TVector4f;
  2463. begin
  2464. SetVector(absPos, AbsolutePosition);
  2465. if RayCastSphereIntersect(rayStart, rayVector, absPos, BoundingSphereRadius, i1, i2) > 0 then
  2466. begin
  2467. Result := True;
  2468. if Assigned(intersectPoint) then
  2469. SetVector(intersectPoint^, i1);
  2470. if Assigned(intersectNormal) then
  2471. begin
  2472. SubtractVector(i1, absPos);
  2473. NormalizeVector(i1);
  2474. SetVector(intersectNormal^, i1);
  2475. end;
  2476. end
  2477. else
  2478. Result := False;
  2479. end;
  2480. function TgxBaseSceneObject.GenerateSilhouette(const SilhouetteParameters: TgxSilhouetteParameters): TgxSilhouette;
  2481. const
  2482. cNbSegments = 21;
  2483. var
  2484. i, j: Integer;
  2485. d, r, vr, s, c, angleFactor: Single;
  2486. sVec, tVec: TAffineVector;
  2487. begin
  2488. r := BoundingSphereRadiusUnscaled;
  2489. d := VectorLength(silhouetteParameters.SeenFrom);
  2490. // determine visible radius
  2491. case silhouetteParameters.Style of
  2492. ssOmni:
  2493. vr := SphereVisibleRadius(d, r);
  2494. ssParallel:
  2495. vr := r;
  2496. else
  2497. Assert(False);
  2498. vr := r;
  2499. end;
  2500. // determine a local orthonormal matrix, viewer-oriented
  2501. sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, XVector);
  2502. if VectorLength(sVec) < 1E-3 then
  2503. sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, YVector);
  2504. tVec := VectorCrossProduct(silhouetteParameters.SeenFrom, sVec);
  2505. NormalizeVector(sVec);
  2506. NormalizeVector(tVec);
  2507. // generate the silhouette (outline and capping)
  2508. Result := TgxSilhouette.Create;
  2509. angleFactor := (2 * PI) / cNbSegments;
  2510. vr := vr * 0.98;
  2511. for i := 0 to cNbSegments - 1 do
  2512. begin
  2513. SinCosine(i * angleFactor, vr, s, c);
  2514. Result.Vertices.AddPoint(VectorCombine(sVec, tVec, s, c));
  2515. j := (i + 1) mod cNbSegments;
  2516. Result.Indices.Add(i, j);
  2517. if silhouetteParameters.CappingRequired then
  2518. Result.CapIndices.Add(cNbSegments, i, j)
  2519. end;
  2520. if silhouetteParameters.CappingRequired then
  2521. Result.Vertices.Add(NullHmgPoint);
  2522. end;
  2523. procedure TgxBaseSceneObject.Assign(Source: TPersistent);
  2524. var
  2525. i: Integer;
  2526. child, newChild: TgxBaseSceneObject;
  2527. begin
  2528. if Assigned(Source) and (Source is TgxBaseSceneObject) then
  2529. begin
  2530. DestroyHandles;
  2531. FVisible := TgxBaseSceneObject(Source).FVisible;
  2532. TgxBaseSceneObject(Source).RebuildMatrix;
  2533. SetMatrix(TgxBaseSceneObject(Source).FLocalMatrix);
  2534. FShowAxes := TgxBaseSceneObject(Source).FShowAxes;
  2535. FObjectsSorting := TgxBaseSceneObject(Source).FObjectsSorting;
  2536. FVisibilityCulling := TgxBaseSceneObject(Source).FVisibilityCulling;
  2537. FRotation.Assign(TgxBaseSceneObject(Source).FRotation);
  2538. DeleteChildren;
  2539. if Assigned(Scene) then
  2540. Scene.BeginUpdate;
  2541. if Assigned(TgxBaseSceneObject(Source).FChildren) then
  2542. begin
  2543. for i := 0 to TgxBaseSceneObject(Source).FChildren.Count - 1 do
  2544. begin
  2545. child := TgxBaseSceneObject(TgxBaseSceneObject(Source).FChildren[i]);
  2546. newChild := AddNewChild(TgxSceneObjectClass(child.ClassType));
  2547. newChild.Assign(child);
  2548. end;
  2549. end;
  2550. if Assigned(Scene) then
  2551. Scene.EndUpdate;
  2552. OnProgress := TgxBaseSceneObject(Source).OnProgress;
  2553. if Assigned(TgxBaseSceneObject(Source).FBehaviours) then
  2554. Behaviours.Assign(TgxBaseSceneObject(Source).Behaviours)
  2555. else
  2556. FreeAndNil(FBehaviours);
  2557. if Assigned(TgxBaseSceneObject(Source).FEffects) then
  2558. Effects.Assign(TgxBaseSceneObject(Source).Effects)
  2559. else
  2560. FreeAndNil(FEffects);
  2561. Tag := TgxBaseSceneObject(Source).Tag;
  2562. FTagFloat := TgxBaseSceneObject(Source).FTagFloat;
  2563. end
  2564. else
  2565. inherited Assign(Source);
  2566. end;
  2567. function TgxBaseSceneObject.IsUpdating: Boolean;
  2568. begin
  2569. Result := (FUpdateCount <> 0) or (csReading in ComponentState);
  2570. end;
  2571. function TgxBaseSceneObject.GetParentComponent: TComponent;
  2572. begin
  2573. if FParent is TgxSceneRootObject then
  2574. Result := FScene
  2575. else
  2576. Result := FParent;
  2577. end;
  2578. function TgxBaseSceneObject.HasParent: Boolean;
  2579. begin
  2580. Result := Assigned(FParent);
  2581. end;
  2582. procedure TgxBaseSceneObject.Lift(ADistance: Single);
  2583. begin
  2584. FPosition.AddScaledVector(ADistance, FUp.AsVector);
  2585. TransformationChanged;
  2586. end;
  2587. procedure TgxBaseSceneObject.Move(ADistance: Single);
  2588. begin
  2589. FPosition.AddScaledVector(ADistance, FDirection.AsVector);
  2590. TransformationChanged;
  2591. end;
  2592. procedure TgxBaseSceneObject.Slide(ADistance: Single);
  2593. begin
  2594. FPosition.AddScaledVector(ADistance, Right);
  2595. TransformationChanged;
  2596. end;
  2597. procedure TgxBaseSceneObject.ResetRotations;
  2598. begin
  2599. FillChar(FLocalMatrix, SizeOf(TMatrix4f), 0);
  2600. FLocalMatrix.x.x := Scale.DirectX;
  2601. FLocalMatrix.y.y := Scale.DirectY;
  2602. FLocalMatrix.z.z := Scale.DirectZ;
  2603. SetVector(FLocalMatrix.W, Position.DirectVector);
  2604. FRotation.DirectVector := NullHmgPoint;
  2605. FDirection.DirectVector := ZHmgVector;
  2606. FUp.DirectVector := YHmgVector;
  2607. TransformationChanged;
  2608. Exclude(FChanges, ocTransformation);
  2609. end;
  2610. procedure TgxBaseSceneObject.ResetAndPitchTurnRoll(const degX, degY, degZ: Single);
  2611. var
  2612. rotMatrix: TMatrix4f;
  2613. v: TVector4f;
  2614. begin
  2615. ResetRotations;
  2616. // set DegX (Pitch)
  2617. rotMatrix := CreateRotationMatrix(Right, degX * cPIdiv180);
  2618. v := VectorTransform(FUp.AsVector, rotMatrix);
  2619. NormalizeVector(v);
  2620. FUp.DirectVector := v;
  2621. v := VectorTransform(FDirection.AsVector, rotMatrix);
  2622. NormalizeVector(v);
  2623. FDirection.DirectVector := v;
  2624. FRotation.DirectX := NormalizeDegAngle(degX);
  2625. // set DegY (Turn)
  2626. rotMatrix := CreateRotationMatrix(FUp.AsVector, degY * cPIdiv180);
  2627. v := VectorTransform(FUp.AsVector, rotMatrix);
  2628. NormalizeVector(v);
  2629. FUp.DirectVector := v;
  2630. v := VectorTransform(FDirection.AsVector, rotMatrix);
  2631. NormalizeVector(v);
  2632. FDirection.DirectVector := v;
  2633. FRotation.DirectY := NormalizeDegAngle(degY);
  2634. // set DegZ (Roll)
  2635. rotMatrix := CreateRotationMatrix(Direction.AsVector, degZ * cPIdiv180);
  2636. v := VectorTransform(FUp.AsVector, rotMatrix);
  2637. NormalizeVector(v);
  2638. FUp.DirectVector := v;
  2639. v := VectorTransform(FDirection.AsVector, rotMatrix);
  2640. NormalizeVector(v);
  2641. FDirection.DirectVector := v;
  2642. FRotation.DirectZ := NormalizeDegAngle(degZ);
  2643. TransformationChanged;
  2644. NotifyChange(Self);
  2645. end;
  2646. procedure TgxBaseSceneObject.RotateAbsolute(const rx, ry, rz: Single);
  2647. var
  2648. resMat: TMatrix4f;
  2649. v: TAffineVector;
  2650. begin
  2651. resMat := Matrix^;
  2652. // No we build rotation matrices and use them to rotate the obj
  2653. if rx <> 0 then
  2654. begin
  2655. SetVector(v, AbsoluteToLocal(XVector));
  2656. resMat := MatrixMultiply(CreateRotationMatrix(v, -DegToRadian(rx)), resMat);
  2657. end;
  2658. if ry <> 0 then
  2659. begin
  2660. SetVector(v, AbsoluteToLocal(YVector));
  2661. resMat := MatrixMultiply(CreateRotationMatrix(v, -DegToRadian(ry)), resMat);
  2662. end;
  2663. if rz <> 0 then
  2664. begin
  2665. SetVector(v, AbsoluteToLocal(ZVector));
  2666. resMat := MatrixMultiply(CreateRotationMatrix(v, -DegToRadian(rz)), resMat);
  2667. end;
  2668. SetMatrix(resMat);
  2669. end;
  2670. procedure TgxBaseSceneObject.RotateAbsolute(const axis: TAffineVector; angle: Single);
  2671. var
  2672. v: TAffineVector;
  2673. begin
  2674. if angle <> 0 then
  2675. begin
  2676. SetVector(v, AbsoluteToLocal(axis));
  2677. SetMatrix(MatrixMultiply(CreateRotationMatrix(v, DegToRadian(angle)), Matrix^));
  2678. end;
  2679. end;
  2680. procedure TgxBaseSceneObject.Pitch(angle: Single);
  2681. var
  2682. r: Single;
  2683. rightVector: TVector4f;
  2684. begin
  2685. FIsCalculating := True;
  2686. try
  2687. angle := -DegToRad(angle);
  2688. rightVector := Right;
  2689. FUp.Rotate(rightVector, angle);
  2690. FUp.Normalize;
  2691. FDirection.Rotate(rightVector, angle);
  2692. FDirection.Normalize;
  2693. r := -RadToDeg(ArcTan2(FDirection.y, VectorLength(FDirection.x, FDirection.z)));
  2694. if FDirection.x < 0 then
  2695. if FDirection.y < 0 then
  2696. r := 180 - r
  2697. else
  2698. r := -180 - r;
  2699. FRotation.x := r;
  2700. finally
  2701. FIsCalculating := False;
  2702. end;
  2703. TransformationChanged;
  2704. end;
  2705. procedure TgxBaseSceneObject.SetPitchAngle(aValue: Single);
  2706. var
  2707. diff: Single;
  2708. rotMatrix: TMatrix4f;
  2709. begin
  2710. if aValue <> FRotation.x then
  2711. begin
  2712. if not(csLoading in ComponentState) then
  2713. begin
  2714. FIsCalculating := True;
  2715. // try
  2716. diff := DegToRadian(FRotation.x - aValue);
  2717. rotMatrix := CreateRotationMatrix(Right, diff);
  2718. FUp.DirectVector := VectorTransform(FUp.AsVector, rotMatrix);
  2719. FUp.Normalize;
  2720. FDirection.DirectVector := VectorTransform(FDirection.AsVector, rotMatrix);
  2721. FDirection.Normalize;
  2722. TransformationChanged;
  2723. // finally
  2724. FIsCalculating := False;
  2725. // end;
  2726. end;
  2727. FRotation.DirectX := NormalizeDegAngle(aValue);
  2728. end;
  2729. end;
  2730. // Roll
  2731. //
  2732. procedure TgxBaseSceneObject.Roll(angle: Single);
  2733. var
  2734. r: Single;
  2735. rightVector, directionVector: TVector4f;
  2736. begin
  2737. FIsCalculating := True;
  2738. try
  2739. angle := DegToRadian(angle);
  2740. directionVector := Direction.AsVector;
  2741. FUp.Rotate(directionVector, angle);
  2742. FUp.Normalize;
  2743. FDirection.Rotate(directionVector, angle);
  2744. FDirection.Normalize;
  2745. // calculate new rotation angle from vectors
  2746. rightVector := Right;
  2747. r := -RadToDeg(ArcTan2(rightVector.y, VectorLength(rightVector.x, rightVector.z)));
  2748. if rightVector.x < 0 then
  2749. if rightVector.y < 0 then
  2750. r := 180 - r
  2751. else
  2752. r := -180 - r;
  2753. FRotation.z := r;
  2754. finally
  2755. FIsCalculating := False;
  2756. end;
  2757. TransformationChanged;
  2758. end;
  2759. procedure TgxBaseSceneObject.SetRollAngle(aValue: Single);
  2760. var
  2761. diff: Single;
  2762. rotMatrix: TMatrix4f;
  2763. begin
  2764. if aValue <> FRotation.z then
  2765. begin
  2766. if not(csLoading in ComponentState) then
  2767. begin
  2768. FIsCalculating := True;
  2769. // try
  2770. diff := DegToRadian(FRotation.z - aValue);
  2771. rotMatrix := CreateRotationMatrix(Direction.AsVector, diff);
  2772. FUp.DirectVector := VectorTransform(FUp.AsVector, rotMatrix);
  2773. FUp.Normalize;
  2774. FDirection.DirectVector := VectorTransform(FDirection.AsVector, rotMatrix);
  2775. FDirection.Normalize;
  2776. TransformationChanged;
  2777. // finally
  2778. FIsCalculating := False;
  2779. // end;
  2780. end;
  2781. FRotation.DirectZ := NormalizeDegAngle(aValue);
  2782. end;
  2783. end;
  2784. procedure TgxBaseSceneObject.Turn(angle: Single);
  2785. var
  2786. r: Single;
  2787. upVector: TVector4f;
  2788. begin
  2789. FIsCalculating := True;
  2790. try
  2791. angle := DegToRadian(angle);
  2792. upVector := Up.AsVector;
  2793. FUp.Rotate(upVector, angle);
  2794. FUp.Normalize;
  2795. FDirection.Rotate(upVector, angle);
  2796. FDirection.Normalize;
  2797. r := -RadToDeg(ArcTan2(FDirection.x, VectorLength(FDirection.y, FDirection.z)));
  2798. if FDirection.x < 0 then
  2799. if FDirection.y < 0 then
  2800. r := 180 - r
  2801. else
  2802. r := -180 - r;
  2803. FRotation.y := r;
  2804. finally
  2805. FIsCalculating := False;
  2806. end;
  2807. TransformationChanged;
  2808. end;
  2809. procedure TgxBaseSceneObject.SetTurnAngle(aValue: Single);
  2810. var
  2811. diff: Single;
  2812. rotMatrix: TMatrix4f;
  2813. begin
  2814. if aValue <> FRotation.y then
  2815. begin
  2816. if not(csLoading in ComponentState) then
  2817. begin
  2818. FIsCalculating := True;
  2819. // try
  2820. diff := DegToRadian(FRotation.y - aValue);
  2821. rotMatrix := CreateRotationMatrix(Up.AsVector, diff);
  2822. FUp.DirectVector := VectorTransform(FUp.AsVector, rotMatrix);
  2823. FUp.Normalize;
  2824. FDirection.DirectVector := VectorTransform(FDirection.AsVector, rotMatrix);
  2825. FDirection.Normalize;
  2826. TransformationChanged;
  2827. // finally
  2828. FIsCalculating := False;
  2829. // end;
  2830. end;
  2831. FRotation.DirectY := NormalizeDegAngle(aValue);
  2832. end;
  2833. end;
  2834. procedure TgxBaseSceneObject.SetRotation(aRotation: TgxCoordinates);
  2835. begin
  2836. FRotation.Assign(aRotation);
  2837. TransformationChanged;
  2838. end;
  2839. function TgxBaseSceneObject.GetPitchAngle: Single;
  2840. begin
  2841. Result := FRotation.x;
  2842. end;
  2843. function TgxBaseSceneObject.GetTurnAngle: Single;
  2844. begin
  2845. Result := FRotation.y;
  2846. end;
  2847. function TgxBaseSceneObject.GetRollAngle: Single;
  2848. begin
  2849. Result := FRotation.z;
  2850. end;
  2851. procedure TgxBaseSceneObject.PointTo(const ATargetObject: TgxBaseSceneObject; const AUpVector: TVector4f);
  2852. begin
  2853. PointTo(ATargetObject.AbsolutePosition, AUpVector);
  2854. end;
  2855. procedure TgxBaseSceneObject.PointTo(const AAbsolutePosition, AUpVector: TVector4f);
  2856. var
  2857. absDir, absRight, absUp: TVector4f;
  2858. begin
  2859. // first compute absolute attitude for pointing
  2860. absDir := VectorSubtract(AAbsolutePosition, Self.AbsolutePosition);
  2861. NormalizeVector(absDir);
  2862. absRight := VectorCrossProduct(absDir, AUpVector);
  2863. NormalizeVector(absRight);
  2864. absUp := VectorCrossProduct(absRight, absDir);
  2865. // convert absolute to local and adjust object
  2866. if Parent <> nil then
  2867. begin
  2868. FDirection.AsVector := Parent.AbsoluteToLocal(absDir);
  2869. FUp.AsVector := Parent.AbsoluteToLocal(absUp);
  2870. end
  2871. else
  2872. begin
  2873. FDirection.AsVector := absDir;
  2874. FUp.AsVector := absUp;
  2875. end;
  2876. TransformationChanged
  2877. end;
  2878. procedure TgxBaseSceneObject.SetShowAxes(aValue: Boolean);
  2879. begin
  2880. if FShowAxes <> aValue then
  2881. begin
  2882. FShowAxes := aValue;
  2883. NotifyChange(Self);
  2884. end;
  2885. end;
  2886. procedure TgxBaseSceneObject.SetScaling(aValue: TgxCoordinates);
  2887. begin
  2888. FScaling.Assign(aValue);
  2889. TransformationChanged;
  2890. end;
  2891. procedure TgxBaseSceneObject.SetName(const NewName: TComponentName);
  2892. begin
  2893. if Name <> NewName then
  2894. begin
  2895. inherited SetName(NewName);
  2896. if Assigned(vBaseSceneObjectNameChangeEvent) then
  2897. vBaseSceneObjectNameChangeEvent(Self);
  2898. end;
  2899. end;
  2900. procedure TgxBaseSceneObject.SetParent(const val: TgxBaseSceneObject);
  2901. begin
  2902. MoveTo(val);
  2903. end;
  2904. function TgxBaseSceneObject.GetIndex: Integer;
  2905. begin
  2906. if Assigned(FParent) then
  2907. Result := FParent.FChildren.IndexOf(Self)
  2908. else
  2909. Result := -1;
  2910. end;
  2911. function TgxBaseSceneObject.GetLocalMatrix: PMatrix4f;
  2912. begin
  2913. Result := @FLocalMatrix;
  2914. end;
  2915. procedure TgxBaseSceneObject.SetIndex(aValue: Integer);
  2916. var
  2917. LCount: Integer;
  2918. parentBackup: TgxBaseSceneObject;
  2919. begin
  2920. if Assigned(FParent) then
  2921. begin
  2922. if aValue < 0 then
  2923. aValue := 0;
  2924. LCount := FParent.Count;
  2925. if aValue >= LCount then
  2926. aValue := LCount - 1;
  2927. if aValue <> Index then
  2928. begin
  2929. if Assigned(FScene) then
  2930. FScene.BeginUpdate;
  2931. parentBackup := FParent;
  2932. parentBackup.Remove(Self, False);
  2933. parentBackup.Insert(aValue, Self);
  2934. if Assigned(FScene) then
  2935. FScene.EndUpdate;
  2936. end;
  2937. end;
  2938. end;
  2939. procedure TgxBaseSceneObject.SetParentComponent(Value: TComponent);
  2940. begin
  2941. inherited;
  2942. if Value = FParent then
  2943. Exit;
  2944. if Value is TgxScene then
  2945. SetParent(TgxScene(Value).Objects)
  2946. else if Value is TgxBaseSceneObject then
  2947. SetParent(TgxBaseSceneObject(Value))
  2948. else
  2949. SetParent(nil);
  2950. end;
  2951. procedure TgxBaseSceneObject.StructureChanged;
  2952. begin
  2953. if not(ocStructure in FChanges) then
  2954. begin
  2955. Include(FChanges, ocStructure);
  2956. NotifyChange(Self);
  2957. end
  2958. else if osDirectDraw in ObjectStyle then
  2959. NotifyChange(Self);
  2960. end;
  2961. procedure TgxBaseSceneObject.ClearStructureChanged;
  2962. begin
  2963. Exclude(FChanges, ocStructure);
  2964. SetBBChanges(BBChanges + [oBBcStructure]);
  2965. end;
  2966. procedure TgxBaseSceneObject.RecTransformationChanged;
  2967. var
  2968. i: Integer;
  2969. List: PgxPointerObjectList;
  2970. matSet: TgxObjectChanges;
  2971. begin
  2972. matSet := [ocAbsoluteMatrix, ocInvAbsoluteMatrix];
  2973. if matSet * FChanges <> matSet then
  2974. begin
  2975. FChanges := FChanges + matSet;
  2976. List := FChildren.List;
  2977. for i := 0 to FChildren.Count - 1 do
  2978. TgxBaseSceneObject(List^[i]).RecTransformationChanged;
  2979. end;
  2980. end;
  2981. procedure TgxBaseSceneObject.TransformationChanged;
  2982. begin
  2983. if not(ocTransformation in FChanges) then
  2984. begin
  2985. Include(FChanges, ocTransformation);
  2986. RecTransformationChanged;
  2987. if not(csLoading in ComponentState) then
  2988. NotifyChange(Self);
  2989. end;
  2990. end;
  2991. procedure TgxBaseSceneObject.MoveTo(newParent: TgxBaseSceneObject);
  2992. begin
  2993. if newParent = FParent then
  2994. Exit;
  2995. if Assigned(FParent) then
  2996. begin
  2997. FParent.Remove(Self, False);
  2998. FParent := nil;
  2999. end;
  3000. if Assigned(newParent) then
  3001. newParent.AddChild(Self)
  3002. else
  3003. SetScene(nil);
  3004. end;
  3005. procedure TgxBaseSceneObject.MoveUp;
  3006. begin
  3007. if Assigned(Parent) then
  3008. Parent.MoveChildUp(Parent.IndexOfChild(Self));
  3009. end;
  3010. procedure TgxBaseSceneObject.MoveDown;
  3011. begin
  3012. if Assigned(Parent) then
  3013. Parent.MoveChildDown(Parent.IndexOfChild(Self));
  3014. end;
  3015. procedure TgxBaseSceneObject.MoveFirst;
  3016. begin
  3017. if Assigned(Parent) then
  3018. Parent.MoveChildFirst(Parent.IndexOfChild(Self));
  3019. end;
  3020. procedure TgxBaseSceneObject.MoveLast;
  3021. begin
  3022. if Assigned(Parent) then
  3023. Parent.MoveChildLast(Parent.IndexOfChild(Self));
  3024. end;
  3025. procedure TgxBaseSceneObject.MoveObjectAround(anObject: TgxBaseSceneObject; pitchDelta, turnDelta: Single);
  3026. var
  3027. originalT2C, normalT2C, normalCameraRight, newPos: TVector4f;
  3028. pitchNow, dist: Single;
  3029. begin
  3030. if Assigned(anObject) then
  3031. begin
  3032. // normalT2C points away from the direction the camera is looking
  3033. originalT2C := VectorSubtract(AbsolutePosition, anObject.AbsolutePosition);
  3034. SetVector(normalT2C, originalT2C);
  3035. dist := VectorLength(normalT2C);
  3036. NormalizeVector(normalT2C);
  3037. // normalRight points to the camera's right
  3038. // the camera is pitching around this axis.
  3039. normalCameraRight := VectorCrossProduct(AbsoluteUp, normalT2C);
  3040. if VectorLength(normalCameraRight) < 0.001 then
  3041. SetVector(normalCameraRight, XVector) // arbitrary vector
  3042. else
  3043. NormalizeVector(normalCameraRight);
  3044. // calculate the current pitch.
  3045. // 0 is looking down and PI is looking up
  3046. pitchNow := ArcCos(VectorDotProduct(AbsoluteUp, normalT2C));
  3047. pitchNow := ClampValue(pitchNow + DegToRad(pitchDelta), 0 + 0.025, PI - 0.025);
  3048. // creates a new vector pointing up and then rotate it down
  3049. // into the new position
  3050. SetVector(normalT2C, AbsoluteUp);
  3051. RotateVector(normalT2C, normalCameraRight, -pitchNow);
  3052. RotateVector(normalT2C, AbsoluteUp, -DegToRadian(turnDelta));
  3053. ScaleVector(normalT2C, dist);
  3054. newPos := VectorAdd(AbsolutePosition, VectorSubtract(normalT2C, originalT2C));
  3055. if Assigned(Parent) then
  3056. newPos := Parent.AbsoluteToLocal(newPos);
  3057. Position.AsVector := newPos;
  3058. end;
  3059. end;
  3060. procedure TgxBaseSceneObject.MoveObjectAllAround(anObject: TgxBaseSceneObject; pitchDelta, turnDelta: Single);
  3061. var
  3062. upVector: TVector4f;
  3063. lookat: TVector4f;
  3064. rightVector: TVector4f;
  3065. tempvector: TVector4f;
  3066. T2C: TVector4f;
  3067. begin
  3068. // if camera has got a target
  3069. if Assigned(anObject) then
  3070. begin
  3071. // vector camera to target
  3072. lookat := VectorNormalize(VectorSubtract(anObject.AbsolutePosition, AbsolutePosition));
  3073. // camera up vector
  3074. upVector := VectorNormalize(AbsoluteUp);
  3075. // if upvector and lookat vector are colinear, it is necessary to compute new up vector
  3076. if Abs(VectorDotProduct(lookat, upVector)) > 0.99 then
  3077. begin
  3078. // X or Y vector use to generate upvector
  3079. SetVector(tempvector, 1, 0, 0);
  3080. // if lookat is colinear to X vector use Y vector to generate upvector
  3081. if Abs(VectorDotProduct(tempvector, lookat)) > 0.99 then
  3082. begin
  3083. SetVector(tempvector, 0, 1, 0);
  3084. end;
  3085. upVector := VectorCrossProduct(tempvector, lookat);
  3086. rightVector := VectorCrossProduct(lookat, upVector);
  3087. end
  3088. else
  3089. begin
  3090. rightVector := VectorCrossProduct(lookat, upVector);
  3091. upVector := VectorCrossProduct(rightVector, lookat);
  3092. end;
  3093. // now the up right and lookat vector are orthogonal
  3094. // vector Target to camera
  3095. T2C := VectorSubtract(AbsolutePosition, anObject.AbsolutePosition);
  3096. RotateVector(T2C, rightVector, DegToRadian(-pitchDelta));
  3097. RotateVector(T2C, upVector, DegToRadian(-turnDelta));
  3098. AbsolutePosition := VectorAdd(anObject.AbsolutePosition, T2C);
  3099. // now update new up vector
  3100. RotateVector(upVector, rightVector, DegToRadian(-pitchDelta));
  3101. AbsoluteUp := upVector;
  3102. AbsoluteDirection := VectorSubtract(anObject.AbsolutePosition, AbsolutePosition);
  3103. end;
  3104. end;
  3105. procedure TgxBaseSceneObject.CoordinateChanged(Sender: TgxCustomCoordinates);
  3106. var
  3107. rightVector: TVector4f;
  3108. begin
  3109. if FIsCalculating then
  3110. Exit;
  3111. FIsCalculating := True;
  3112. try
  3113. if Sender = FDirection then
  3114. begin
  3115. if FDirection.VectorLength = 0 then
  3116. FDirection.DirectVector := ZHmgVector;
  3117. FDirection.Normalize;
  3118. // adjust up vector
  3119. rightVector := VectorCrossProduct(FDirection.AsVector, FUp.AsVector);
  3120. // Rightvector is zero if direction changed exactly by 90 degrees,
  3121. // in this case assume a default vector
  3122. if VectorLength(rightVector) < 1E-5 then
  3123. begin
  3124. rightVector := VectorCrossProduct(ZHmgVector, FUp.AsVector);
  3125. if VectorLength(rightVector) < 1E-5 then
  3126. rightVector := VectorCrossProduct(XHmgVector, FUp.AsVector);
  3127. end;
  3128. FUp.DirectVector := VectorCrossProduct(rightVector, FDirection.AsVector);
  3129. FUp.Normalize;
  3130. end
  3131. else if Sender = FUp then
  3132. begin
  3133. if FUp.VectorLength = 0 then
  3134. FUp.DirectVector := YHmgVector;
  3135. FUp.Normalize;
  3136. // adjust up vector
  3137. rightVector := VectorCrossProduct(FDirection.AsVector, FUp.AsVector);
  3138. // Rightvector is zero if direction changed exactly by 90 degrees,
  3139. // in this case assume a default vector
  3140. if VectorLength(rightVector) < 1E-5 then
  3141. begin
  3142. rightVector := VectorCrossProduct(ZHmgVector, FUp.AsVector);
  3143. if VectorLength(rightVector) < 1E-5 then
  3144. rightVector := VectorCrossProduct(XHmgVector, FUp.AsVector);
  3145. end;
  3146. FDirection.DirectVector := VectorCrossProduct(FUp.AsVector, rightVector);
  3147. FDirection.Normalize;
  3148. end;
  3149. TransformationChanged;
  3150. finally
  3151. FIsCalculating := False;
  3152. end;
  3153. end;
  3154. procedure TgxBaseSceneObject.DoProgress(const progressTime: TgxProgressTimes);
  3155. var
  3156. i: Integer;
  3157. begin
  3158. for i := FChildren.Count - 1 downto 0 do
  3159. TgxBaseSceneObject(FChildren.List^[i]).DoProgress(progressTime);
  3160. if Assigned(FBehaviours) then
  3161. FBehaviours.DoProgress(progressTime);
  3162. if Assigned(FEffects) then
  3163. FEffects.DoProgress(progressTime);
  3164. if Assigned(FOnProgress) then
  3165. with progressTime do
  3166. FOnProgress(Self, deltaTime, newTime);
  3167. end;
  3168. procedure TgxBaseSceneObject.Insert(AIndex: Integer; AChild: TgxBaseSceneObject);
  3169. begin
  3170. with FChildren do
  3171. begin
  3172. if Assigned(AChild.FParent) then
  3173. AChild.FParent.Remove(AChild, False);
  3174. Insert(AIndex, AChild);
  3175. end;
  3176. AChild.FParent := Self;
  3177. if AChild.FScene <> FScene then
  3178. AChild.DestroyHandles;
  3179. AChild.SetScene(FScene);
  3180. if Assigned(FScene) then
  3181. FScene.AddLights(AChild);
  3182. AChild.TransformationChanged;
  3183. AChild.DoOnAddedToParent;
  3184. end;
  3185. procedure TgxBaseSceneObject.Remove(AChild: TgxBaseSceneObject; keepChildren: Boolean);
  3186. var
  3187. i: Integer;
  3188. begin
  3189. if not Assigned(FChildren) then
  3190. Exit;
  3191. if AChild.Parent = Self then
  3192. begin
  3193. if Assigned(FScene) then
  3194. FScene.RemoveLights(AChild);
  3195. if AChild.Owner = Self then
  3196. RemoveComponent(AChild);
  3197. FChildren.Remove(AChild);
  3198. AChild.FParent := nil;
  3199. if keepChildren then
  3200. begin
  3201. BeginUpdate;
  3202. if AChild.Count <> 0 then
  3203. for i := AChild.Count - 1 downto 0 do
  3204. if not IsSubComponent(AChild.Children[i]) then
  3205. AChild.Children[i].MoveTo(Self);
  3206. EndUpdate;
  3207. end
  3208. else
  3209. NotifyChange(Self);
  3210. end;
  3211. end;
  3212. function TgxBaseSceneObject.IndexOfChild(AChild: TgxBaseSceneObject): Integer;
  3213. begin
  3214. Result := FChildren.IndexOf(AChild)
  3215. end;
  3216. function TgxBaseSceneObject.FindChild(const aName: string; ownChildrenOnly: Boolean): TgxBaseSceneObject;
  3217. var
  3218. i: Integer;
  3219. res: TgxBaseSceneObject;
  3220. begin
  3221. res := nil;
  3222. Result := nil;
  3223. for i := 0 to FChildren.Count - 1 do
  3224. begin
  3225. if CompareText(TgxBaseSceneObject(FChildren[i]).Name, aName) = 0 then
  3226. begin
  3227. res := TgxBaseSceneObject(FChildren[i]);
  3228. Break;
  3229. end;
  3230. end;
  3231. if not ownChildrenOnly then
  3232. begin
  3233. for i := 0 to FChildren.Count - 1 do
  3234. with TgxBaseSceneObject(FChildren[i]) do
  3235. begin
  3236. Result := FindChild(aName, ownChildrenOnly);
  3237. if Assigned(Result) then
  3238. Break;
  3239. end;
  3240. end;
  3241. if not Assigned(Result) then
  3242. Result := res;
  3243. end;
  3244. procedure TgxBaseSceneObject.ExchangeChildren(anIndex1, anIndex2: Integer);
  3245. begin
  3246. Assert(Assigned(FChildren), 'No children found!');
  3247. FChildren.Exchange(anIndex1, anIndex2);
  3248. NotifyChange(Self);
  3249. end;
  3250. procedure TgxBaseSceneObject.ExchangeChildrenSafe(anIndex1, anIndex2: Integer);
  3251. begin
  3252. Assert(Assigned(FChildren), 'No children found!');
  3253. if (anIndex1 < FChildren.Count) and (anIndex2 < FChildren.Count) and (anIndex1 > -1) and (anIndex2 > -1) and
  3254. (anIndex1 <> anIndex2) then
  3255. begin
  3256. FChildren.Exchange(anIndex1, anIndex2);
  3257. NotifyChange(Self);
  3258. end;
  3259. end;
  3260. procedure TgxBaseSceneObject.MoveChildUp(anIndex: Integer);
  3261. begin
  3262. Assert(Assigned(FChildren), 'No children found!');
  3263. if anIndex > 0 then
  3264. begin
  3265. FChildren.Exchange(anIndex, anIndex - 1);
  3266. NotifyChange(Self);
  3267. end;
  3268. end;
  3269. procedure TgxBaseSceneObject.MoveChildDown(anIndex: Integer);
  3270. begin
  3271. Assert(Assigned(FChildren), 'No children found!');
  3272. if anIndex < FChildren.Count - 1 then
  3273. begin
  3274. FChildren.Exchange(anIndex, anIndex + 1);
  3275. NotifyChange(Self);
  3276. end;
  3277. end;
  3278. procedure TgxBaseSceneObject.MoveChildFirst(anIndex: Integer);
  3279. begin
  3280. Assert(Assigned(FChildren), 'No children found!');
  3281. if anIndex <> 0 then
  3282. begin
  3283. FChildren.Move(anIndex, 0);
  3284. NotifyChange(Self);
  3285. end;
  3286. end;
  3287. procedure TgxBaseSceneObject.MoveChildLast(anIndex: Integer);
  3288. begin
  3289. Assert(Assigned(FChildren), 'No children found!');
  3290. if anIndex <> FChildren.Count - 1 then
  3291. begin
  3292. FChildren.Move(anIndex, FChildren.Count - 1);
  3293. NotifyChange(Self);
  3294. end;
  3295. end;
  3296. procedure TgxBaseSceneObject.Render(var ARci: TgxRenderContextInfo);
  3297. var
  3298. shouldRenderSelf, shouldRenderChildren: Boolean;
  3299. aabb: TAABB;
  3300. master: TObject;
  3301. begin
  3302. {$IFDEF USE_OPENGL_DEBUG}
  3303. if GL_GREMEDY_string_marker then
  3304. GL_StringMarkerGREMEDY(Length(Name) + Length('.Render'), PGLChar(String(Name + '.Render')));
  3305. {$ENDIF}
  3306. if (ARci.drawState = dsPicking) and not FPickable then
  3307. Exit;
  3308. // visibility culling determination
  3309. if ARci.VisibilityCulling in [vcObjectBased, vcHierarchical] then
  3310. begin
  3311. if ARci.VisibilityCulling = vcObjectBased then
  3312. begin
  3313. shouldRenderSelf := (osNoVisibilityCulling in ObjectStyle) or
  3314. (not IsVolumeClipped(BarycenterAbsolutePosition, BoundingSphereRadius, ARci.rcci.frustum));
  3315. shouldRenderChildren := Assigned(FChildren);
  3316. end
  3317. else
  3318. begin // vcHierarchical
  3319. aabb := AxisAlignedBoundingBox;
  3320. shouldRenderSelf := (osNoVisibilityCulling in ObjectStyle) or
  3321. (not IsVolumeClipped(aabb.min, aabb.max, ARci.rcci.frustum));
  3322. shouldRenderChildren := shouldRenderSelf and Assigned(FChildren);
  3323. end;
  3324. if not(shouldRenderSelf or shouldRenderChildren) then
  3325. Exit;
  3326. end
  3327. else
  3328. begin
  3329. Assert(ARci.VisibilityCulling in [vcNone, vcInherited], 'Unknown visibility culling option');
  3330. shouldRenderSelf := True;
  3331. shouldRenderChildren := FChildren.Count > 0;
  3332. end;
  3333. // Prepare Matrix and PickList stuff
  3334. ARci.PipeLineTransformation.Push;
  3335. if ocTransformation in FChanges then
  3336. RebuildMatrix;
  3337. if ARci.proxySubObject then
  3338. ARci.PipeLineTransformation.SetModelMatrix(MatrixMultiply(LocalMatrix^, ARci.PipeLineTransformation.ModelMatrix^))
  3339. else
  3340. ARci.PipeLineTransformation.SetModelMatrix(AbsoluteMatrix);
  3341. master := nil;
  3342. if ARci.drawState = dsPicking then
  3343. begin
  3344. if ARci.proxySubObject then
  3345. master := TgxSceneBuffer(ARci.Buffer).FSelector.CurrentObject;
  3346. TgxSceneBuffer(ARci.Buffer).FSelector.CurrentObject := Self;
  3347. end;
  3348. // Start rendering
  3349. if shouldRenderSelf then
  3350. begin
  3351. vCurrentRenderingObject := Self;
  3352. {$IFNDEF USE_OPTIMIZATIONS}
  3353. if FShowAxes then
  3354. DrawAxes(ARci, $CCCC);
  3355. {$ENDIF}
  3356. if Assigned(FEffects) and (FEffects.Count > 0) then
  3357. begin
  3358. ARci.PipeLineTransformation.Push;
  3359. FEffects.RenderPreEffects(ARci);
  3360. ARci.PipeLineTransformation.Pop;
  3361. ARci.PipeLineTransformation.Push;
  3362. if osIgnoreDepthBuffer in ObjectStyle then
  3363. begin
  3364. ARci.gxStates.Disable(stDepthTest);
  3365. DoRender(ARci, True, shouldRenderChildren);
  3366. ARci.gxStates.Enable(stDepthTest);
  3367. end
  3368. else
  3369. DoRender(ARci, True, shouldRenderChildren);
  3370. FEffects.RenderPostEffects(ARci);
  3371. ARci.PipeLineTransformation.Pop;
  3372. end
  3373. else
  3374. begin
  3375. if osIgnoreDepthBuffer in ObjectStyle then
  3376. begin
  3377. ARci.gxStates.Disable(stDepthTest);
  3378. DoRender(ARci, True, shouldRenderChildren);
  3379. ARci.gxStates.Enable(stDepthTest);
  3380. end
  3381. else
  3382. DoRender(ARci, True, shouldRenderChildren);
  3383. end;
  3384. vCurrentRenderingObject := nil;
  3385. end
  3386. else
  3387. begin
  3388. if (osIgnoreDepthBuffer in ObjectStyle) and TgxSceneBuffer(ARci.Buffer).DepthTest then
  3389. begin
  3390. ARci.gxStates.Disable(stDepthTest);
  3391. DoRender(ARci, False, shouldRenderChildren);
  3392. ARci.gxStates.Enable(stDepthTest);
  3393. end
  3394. else
  3395. DoRender(ARci, False, shouldRenderChildren);
  3396. end;
  3397. // Pop Name & Matrix
  3398. if Assigned(master) then
  3399. TgxSceneBuffer(ARci.Buffer).FSelector.CurrentObject := master;
  3400. ARci.PipeLineTransformation.Pop;
  3401. end;
  3402. procedure TgxBaseSceneObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
  3403. begin
  3404. // start rendering self
  3405. if ARenderSelf then
  3406. begin
  3407. if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
  3408. BuildList(ARci)
  3409. else
  3410. ARci.gxStates.CallList(GetHandle(ARci));
  3411. end;
  3412. // start rendering children (if any)
  3413. if ARenderChildren then
  3414. Self.RenderChildren(0, Count - 1, ARci);
  3415. end;
  3416. procedure TgxBaseSceneObject.RenderChildren(firstChildIndex, lastChildIndex: Integer; var rci: TgxRenderContextInfo);
  3417. var
  3418. i: Integer;
  3419. plist: PgxPointerObjectList;
  3420. obj: TgxBaseSceneObject;
  3421. oldSorting: TgxObjectsSorting;
  3422. oldCulling: TgxVisibilityCulling;
  3423. begin
  3424. oldCulling := rci.VisibilityCulling;
  3425. if Self.VisibilityCulling <> vcInherited then
  3426. rci.VisibilityCulling := Self.VisibilityCulling;
  3427. if lastChildIndex = firstChildIndex then
  3428. begin
  3429. obj := TgxBaseSceneObject(FChildren.List^[firstChildIndex]);
  3430. if obj.Visible then
  3431. obj.Render(rci)
  3432. end
  3433. else if lastChildIndex > firstChildIndex then
  3434. begin
  3435. oldSorting := rci.ObjectsSorting;
  3436. if Self.ObjectsSorting <> osInherited then
  3437. rci.ObjectsSorting := Self.ObjectsSorting;
  3438. case rci.ObjectsSorting of
  3439. osNone:
  3440. begin
  3441. plist := FChildren.List;
  3442. for i := firstChildIndex to lastChildIndex do
  3443. begin
  3444. obj := TgxBaseSceneObject(plist^[i]);
  3445. if obj.Visible then
  3446. obj.Render(rci);
  3447. end;
  3448. end;
  3449. osRenderFarthestFirst, osRenderBlendedLast, osRenderNearestFirst:
  3450. begin
  3451. distList.Flush;
  3452. objList.Count := 0;
  3453. distList.GrowthDelta := lastChildIndex + 1; // no reallocations
  3454. objList.GrowthDelta := distList.GrowthDelta;
  3455. // try
  3456. case rci.ObjectsSorting of
  3457. osRenderBlendedLast:
  3458. // render opaque stuff
  3459. for i := firstChildIndex to lastChildIndex do
  3460. begin
  3461. obj := TgxBaseSceneObject(FChildren.List^[i]);
  3462. if obj.Visible then
  3463. begin
  3464. if not obj.Blended then
  3465. obj.Render(rci)
  3466. else
  3467. begin
  3468. objList.Add(obj);
  3469. distList.Add(1 + obj.BarycenterSqrDistanceTo(rci.cameraPosition));
  3470. end;
  3471. end;
  3472. end;
  3473. osRenderFarthestFirst:
  3474. for i := firstChildIndex to lastChildIndex do
  3475. begin
  3476. obj := TgxBaseSceneObject(FChildren.List^[i]);
  3477. if obj.Visible then
  3478. begin
  3479. objList.Add(obj);
  3480. distList.Add(1 + obj.BarycenterSqrDistanceTo(rci.cameraPosition));
  3481. end;
  3482. end;
  3483. osRenderNearestFirst:
  3484. for i := firstChildIndex to lastChildIndex do
  3485. begin
  3486. obj := TgxBaseSceneObject(FChildren.List^[i]);
  3487. if obj.Visible then
  3488. begin
  3489. objList.Add(obj);
  3490. distList.Add(-1 - obj.BarycenterSqrDistanceTo(rci.cameraPosition));
  3491. end;
  3492. end;
  3493. else
  3494. Assert(False);
  3495. end;
  3496. if distList.Count > 0 then
  3497. begin
  3498. if distList.Count > 1 then
  3499. FastQuickSortLists(0, distList.Count - 1, distList, objList);
  3500. plist := objList.List;
  3501. for i := objList.Count - 1 downto 0 do
  3502. TgxBaseSceneObject(plist^[i]).Render(rci);
  3503. end;
  3504. // finally
  3505. // end;
  3506. end;
  3507. else
  3508. Assert(False);
  3509. end;
  3510. rci.ObjectsSorting := oldSorting;
  3511. end;
  3512. rci.VisibilityCulling := oldCulling;
  3513. end;
  3514. procedure TgxBaseSceneObject.NotifyChange(Sender: TObject);
  3515. begin
  3516. if Assigned(FScene) and (not IsUpdating) then
  3517. FScene.NotifyChange(Self);
  3518. end;
  3519. function TgxBaseSceneObject.GetMatrix: PMatrix4f;
  3520. begin
  3521. RebuildMatrix;
  3522. Result := @FLocalMatrix;
  3523. end;
  3524. procedure TgxBaseSceneObject.SetMatrix(const aValue: TMatrix4f);
  3525. begin
  3526. FLocalMatrix := aValue;
  3527. FDirection.DirectVector := VectorNormalize(FLocalMatrix.z);
  3528. FUp.DirectVector := VectorNormalize(FLocalMatrix.y);
  3529. Scale.SetVector(VectorLength(FLocalMatrix.x), VectorLength(FLocalMatrix.y), VectorLength(FLocalMatrix.z), 0);
  3530. FPosition.DirectVector := FLocalMatrix.W;
  3531. TransformationChanged;
  3532. end;
  3533. procedure TgxBaseSceneObject.SetPosition(APosition: TgxCoordinates);
  3534. begin
  3535. FPosition.SetPoint(APosition.DirectX, APosition.DirectY, APosition.DirectZ);
  3536. end;
  3537. procedure TgxBaseSceneObject.SetDirection(AVector: TgxCoordinates);
  3538. begin
  3539. if not VectorIsNull(AVector.DirectVector) then
  3540. FDirection.SetVector(AVector.DirectX, AVector.DirectY, AVector.DirectZ);
  3541. end;
  3542. procedure TgxBaseSceneObject.SetUp(AVector: TgxCoordinates);
  3543. begin
  3544. if not VectorIsNull(AVector.DirectVector) then
  3545. FUp.SetVector(AVector.DirectX, AVector.DirectY, AVector.DirectZ);
  3546. end;
  3547. function TgxBaseSceneObject.GetVisible: Boolean;
  3548. begin
  3549. Result := FVisible;
  3550. end;
  3551. function TgxBaseSceneObject.GetPickable: Boolean;
  3552. begin
  3553. Result := FPickable;
  3554. end;
  3555. procedure TgxBaseSceneObject.SetVisible(aValue: Boolean);
  3556. begin
  3557. if FVisible <> aValue then
  3558. begin
  3559. FVisible := aValue;
  3560. NotifyChange(Self);
  3561. end;
  3562. end;
  3563. procedure TgxBaseSceneObject.SetPickable(aValue: Boolean);
  3564. begin
  3565. if FPickable <> aValue then
  3566. begin
  3567. FPickable := aValue;
  3568. NotifyChange(Self);
  3569. end;
  3570. end;
  3571. procedure TgxBaseSceneObject.SetObjectsSorting(const val: TgxObjectsSorting);
  3572. begin
  3573. if FObjectsSorting <> val then
  3574. begin
  3575. FObjectsSorting := val;
  3576. NotifyChange(Self);
  3577. end;
  3578. end;
  3579. procedure TgxBaseSceneObject.SetVisibilityCulling(const val: TgxVisibilityCulling);
  3580. begin
  3581. if FVisibilityCulling <> val then
  3582. begin
  3583. FVisibilityCulling := val;
  3584. NotifyChange(Self);
  3585. end;
  3586. end;
  3587. procedure TgxBaseSceneObject.SetBehaviours(const val: TgxBehaviours);
  3588. begin
  3589. Behaviours.Assign(val);
  3590. end;
  3591. function TgxBaseSceneObject.GetBehaviours: TgxBehaviours;
  3592. begin
  3593. if not Assigned(FBehaviours) then
  3594. FBehaviours := TgxBehaviours.Create(Self);
  3595. Result := FBehaviours;
  3596. end;
  3597. procedure TgxBaseSceneObject.SetEffects(const val: TgxEffects);
  3598. begin
  3599. Effects.Assign(val);
  3600. end;
  3601. function TgxBaseSceneObject.GetEffects: TgxEffects;
  3602. begin
  3603. if not Assigned(FEffects) then
  3604. FEffects := TgxEffects.Create(Self);
  3605. Result := FEffects;
  3606. end;
  3607. procedure TgxBaseSceneObject.SetScene(const Value: TgxScene);
  3608. var
  3609. i: Integer;
  3610. begin
  3611. if Value <> FScene then
  3612. begin
  3613. // must be freed, the new scene may be using a non-compatible RC
  3614. if FScene <> nil then
  3615. DestroyHandles;
  3616. FScene := Value;
  3617. // propagate for childs
  3618. if Assigned(FChildren) then
  3619. for i := 0 to FChildren.Count - 1 do
  3620. Children[i].SetScene(FScene);
  3621. end;
  3622. end;
  3623. procedure TgxBaseSceneObject.Translate(tx, ty, tz: Single);
  3624. begin
  3625. FPosition.Translate(AffineVectorMake(tx, ty, tz));
  3626. end;
  3627. function TgxBaseSceneObject.GetAbsoluteAffinePosition: TAffineVector;
  3628. var
  3629. temp: TVector4f;
  3630. begin
  3631. temp := GetAbsolutePosition;
  3632. Result := AffineVectorMake(temp.x, temp.y, temp.z);
  3633. end;
  3634. function TgxBaseSceneObject.GetAbsoluteAffineDirection: TAffineVector;
  3635. var
  3636. temp: TVector4f;
  3637. begin
  3638. temp := GetAbsoluteDirection;
  3639. Result := AffineVectorMake(temp.x, temp.y, temp.z);
  3640. end;
  3641. function TgxBaseSceneObject.GetAbsoluteAffineUp: TAffineVector;
  3642. var
  3643. temp: TVector4f;
  3644. begin
  3645. temp := GetAbsoluteUp;
  3646. Result := AffineVectorMake(temp.x, temp.y, temp.z);
  3647. end;
  3648. procedure TgxBaseSceneObject.SetAbsoluteAffinePosition(const Value: TAffineVector);
  3649. begin
  3650. SetAbsolutePosition(VectorMake(Value, 1));
  3651. end;
  3652. procedure TgxBaseSceneObject.SetAbsoluteAffineUp(const v: TAffineVector);
  3653. begin
  3654. SetAbsoluteUp(VectorMake(v, 1));
  3655. end;
  3656. procedure TgxBaseSceneObject.SetAbsoluteAffineDirection(const v: TAffineVector);
  3657. begin
  3658. SetAbsoluteDirection(VectorMake(v, 1));
  3659. end;
  3660. function TgxBaseSceneObject.AffineLeftVector: TAffineVector;
  3661. begin
  3662. Result := AffineVectorMake(LeftVector);
  3663. end;
  3664. function TgxBaseSceneObject.AffineRight: TAffineVector;
  3665. begin
  3666. Result := AffineVectorMake(Right);
  3667. end;
  3668. function TgxBaseSceneObject.DistanceTo(const pt: TAffineVector): Single;
  3669. begin
  3670. Result := VectorDistance(AbsoluteAffinePosition, pt);
  3671. end;
  3672. function TgxBaseSceneObject.SqrDistanceTo(const pt: TAffineVector): Single;
  3673. begin
  3674. Result := VectorDistance2(AbsoluteAffinePosition, pt);
  3675. end;
  3676. procedure TgxBaseSceneObject.DoOnAddedToParent;
  3677. begin
  3678. if Assigned(FOnAddedToParent) then
  3679. FOnAddedToParent(Self);
  3680. end;
  3681. function TgxBaseSceneObject.GetAbsoluteAffineScale: TAffineVector;
  3682. begin
  3683. Result := AffineVectorMake(GetAbsoluteScale);
  3684. end;
  3685. procedure TgxBaseSceneObject.SetAbsoluteAffineScale(const Value: TAffineVector);
  3686. begin
  3687. SetAbsoluteScale(VectorMake(Value, GetAbsoluteScale.W));
  3688. end;
  3689. // ------------------
  3690. // ------------------ TgxBaseBehaviour ------------------
  3691. // ------------------
  3692. constructor TgxBaseBehaviour.Create(AOwner: TXCollection);
  3693. begin
  3694. inherited Create(AOwner);
  3695. // nothing more, yet
  3696. end;
  3697. destructor TgxBaseBehaviour.Destroy;
  3698. begin
  3699. // nothing more, yet
  3700. inherited Destroy;
  3701. end;
  3702. procedure TgxBaseBehaviour.SetName(const val: string);
  3703. begin
  3704. inherited SetName(val);
  3705. if Assigned(vBehaviourNameChangeEvent) then
  3706. vBehaviourNameChangeEvent(Self);
  3707. end;
  3708. procedure TgxBaseBehaviour.WriteToFiler(writer: TWriter);
  3709. begin
  3710. inherited;
  3711. with writer do
  3712. begin
  3713. WriteInteger(0); // Archive Version 0
  3714. // nothing more, yet
  3715. end;
  3716. end;
  3717. procedure TgxBaseBehaviour.ReadFromFiler(reader: TReader);
  3718. begin
  3719. if Owner.ArchiveVersion > 0 then
  3720. inherited;
  3721. with reader do
  3722. begin
  3723. if ReadInteger <> 0 then
  3724. Assert(False);
  3725. // nothing more, yet
  3726. end;
  3727. end;
  3728. function TgxBaseBehaviour.OwnerBaseSceneObject: TgxBaseSceneObject;
  3729. begin
  3730. Result := TgxBaseSceneObject(Owner.Owner);
  3731. end;
  3732. procedure TgxBaseBehaviour.DoProgress(const progressTime: TgxProgressTimes);
  3733. begin
  3734. // does nothing
  3735. end;
  3736. // ------------------
  3737. // ------------------ TgxBehaviours ------------------
  3738. // ------------------
  3739. // Create
  3740. //
  3741. constructor TgxBehaviours.Create(AOwner: TPersistent);
  3742. begin
  3743. Assert(AOwner is TgxBaseSceneObject);
  3744. inherited Create(AOwner);
  3745. end;
  3746. function TgxBehaviours.GetNamePath: string;
  3747. var
  3748. s: string;
  3749. begin
  3750. Result := ClassName;
  3751. if GetOwner = nil then
  3752. Exit;
  3753. s := GetOwner.GetNamePath;
  3754. if s = '' then
  3755. Exit;
  3756. Result := s + '.Behaviours';
  3757. end;
  3758. class function TgxBehaviours.ItemsClass: TXCollectionItemClass;
  3759. begin
  3760. Result := TgxBehaviour;
  3761. end;
  3762. function TgxBehaviours.GetBehaviour(Index: Integer): TgxBehaviour;
  3763. begin
  3764. Result := TgxBehaviour(Items[index]);
  3765. end;
  3766. function TgxBehaviours.CanAdd(aClass: TXCollectionItemClass): Boolean;
  3767. begin
  3768. Result := (not aClass.InheritsFrom(TgxEffect)) and (inherited CanAdd(aClass));
  3769. end;
  3770. procedure TgxBehaviours.DoProgress(const progressTimes: TgxProgressTimes);
  3771. var
  3772. i: Integer;
  3773. begin
  3774. for i := 0 to Count - 1 do
  3775. TgxBehaviour(Items[i]).DoProgress(progressTimes);
  3776. end;
  3777. // ------------------
  3778. // ------------------ TgxEffect ------------------
  3779. // ------------------
  3780. procedure TgxEffect.WriteToFiler(writer: TWriter);
  3781. begin
  3782. inherited;
  3783. with writer do
  3784. begin
  3785. WriteInteger(0); // Archive Version 0
  3786. // nothing more, yet
  3787. end;
  3788. end;
  3789. procedure TgxEffect.ReadFromFiler(reader: TReader);
  3790. begin
  3791. if Owner.ArchiveVersion > 0 then
  3792. inherited;
  3793. with reader do
  3794. begin
  3795. if ReadInteger <> 0 then
  3796. Assert(False);
  3797. // nothing more, yet
  3798. end;
  3799. end;
  3800. procedure TgxEffect.Render(var rci: TgxRenderContextInfo);
  3801. begin
  3802. // nothing here, this implem is just to avoid "abstract error"
  3803. end;
  3804. // ------------------
  3805. // ------------------ TgxEffects ------------------
  3806. // ------------------
  3807. constructor TgxEffects.Create(AOwner: TPersistent);
  3808. begin
  3809. Assert(AOwner is TgxBaseSceneObject);
  3810. inherited Create(AOwner);
  3811. end;
  3812. function TgxEffects.GetNamePath: string;
  3813. var
  3814. s: string;
  3815. begin
  3816. Result := ClassName;
  3817. if GetOwner = nil then
  3818. Exit;
  3819. s := GetOwner.GetNamePath;
  3820. if s = '' then
  3821. Exit;
  3822. Result := s + '.Effects';
  3823. end;
  3824. class function TgxEffects.ItemsClass: TXCollectionItemClass;
  3825. begin
  3826. Result := TgxEffect;
  3827. end;
  3828. function TgxEffects.GetEffect(Index: Integer): TgxEffect;
  3829. begin
  3830. Result := TgxEffect(Items[index]);
  3831. end;
  3832. function TgxEffects.CanAdd(aClass: TXCollectionItemClass): Boolean;
  3833. begin
  3834. Result := (aClass.InheritsFrom(TgxEffect)) and (inherited CanAdd(aClass));
  3835. end;
  3836. procedure TgxEffects.DoProgress(const progressTime: TgxProgressTimes);
  3837. var
  3838. i: Integer;
  3839. begin
  3840. for i := 0 to Count - 1 do
  3841. TgxEffect(Items[i]).DoProgress(progressTime);
  3842. end;
  3843. procedure TgxEffects.RenderPreEffects(var rci: TgxRenderContextInfo);
  3844. var
  3845. i: Integer;
  3846. effect: TgxEffect;
  3847. begin
  3848. for i := 0 to Count - 1 do
  3849. begin
  3850. effect := TgxEffect(Items[i]);
  3851. if effect is TgxObjectPreEffect then
  3852. effect.Render(rci);
  3853. end;
  3854. end;
  3855. procedure TgxEffects.RenderPostEffects(var rci: TgxRenderContextInfo);
  3856. var
  3857. i: Integer;
  3858. effect: TgxEffect;
  3859. begin
  3860. for i := 0 to Count - 1 do
  3861. begin
  3862. effect := TgxEffect(Items[i]);
  3863. if effect is TgxObjectPostEffect then
  3864. effect.Render(rci)
  3865. else if Assigned(rci.afterRenderEffects) and (effect is TgxObjectAfterEffect) then
  3866. rci.afterRenderEffects.Add(effect);
  3867. end;
  3868. end;
  3869. // ------------------
  3870. // ------------------ TgxCustomSceneObject ------------------
  3871. // ------------------
  3872. constructor TgxCustomSceneObject.Create(AOwner: TComponent);
  3873. begin
  3874. inherited Create(AOwner);
  3875. FMaterial := TgxMaterial.Create(Self);
  3876. end;
  3877. destructor TgxCustomSceneObject.Destroy;
  3878. begin
  3879. inherited Destroy;
  3880. FMaterial.Free;
  3881. end;
  3882. procedure TgxCustomSceneObject.Assign(Source: TPersistent);
  3883. begin
  3884. if Source is TgxCustomSceneObject then
  3885. begin
  3886. FMaterial.Assign(TgxCustomSceneObject(Source).FMaterial);
  3887. FHint := TgxCustomSceneObject(Source).FHint;
  3888. end;
  3889. inherited Assign(Source);
  3890. end;
  3891. function TgxCustomSceneObject.Blended: Boolean;
  3892. begin
  3893. Result := Material.Blended;
  3894. end;
  3895. procedure TgxCustomSceneObject.Loaded;
  3896. begin
  3897. inherited;
  3898. FMaterial.Loaded;
  3899. end;
  3900. procedure TgxCustomSceneObject.SetVKMaterial(aValue: TgxMaterial);
  3901. begin
  3902. FMaterial.Assign(aValue);
  3903. NotifyChange(Self);
  3904. end;
  3905. procedure TgxCustomSceneObject.DestroyHandle;
  3906. begin
  3907. inherited;
  3908. FMaterial.DestroyHandles;
  3909. end;
  3910. procedure TgxCustomSceneObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
  3911. begin
  3912. // start rendering self
  3913. if ARenderSelf then
  3914. if ARci.ignoreMaterials then
  3915. if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
  3916. BuildList(ARci)
  3917. else
  3918. ARci.gxStates.CallList(GetHandle(ARci))
  3919. else
  3920. begin
  3921. FMaterial.Apply(ARci);
  3922. repeat
  3923. if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
  3924. BuildList(ARci)
  3925. else
  3926. ARci.gxStates.CallList(GetHandle(ARci));
  3927. until not FMaterial.UnApply(ARci);
  3928. end;
  3929. // start rendering children (if any)
  3930. if ARenderChildren then
  3931. Self.RenderChildren(0, Count - 1, ARci);
  3932. end;
  3933. // ------------------
  3934. // ------------------ TgxSceneRootObject ------------------
  3935. // ------------------
  3936. constructor TgxSceneRootObject.Create(AOwner: TComponent);
  3937. begin
  3938. Assert(AOwner is TgxScene);
  3939. inherited Create(AOwner);
  3940. ObjectStyle := ObjectStyle + [osDirectDraw];
  3941. FScene := TgxScene(AOwner);
  3942. end;
  3943. // ------------------
  3944. // ------------------ TgxCamera ------------------
  3945. // ------------------
  3946. constructor TgxCamera.Create(AOwner: TComponent);
  3947. begin
  3948. inherited Create(AOwner);
  3949. FFocalLength := 50;
  3950. FDepthOfView := 100;
  3951. FNearPlaneBias := 1;
  3952. FDirection.Initialize(VectorMake(0, 0, -1, 0));
  3953. FCameraStyle := csPerspective;
  3954. FSceneScale := 1;
  3955. FDesign := False;
  3956. FFOVY := -1;
  3957. FKeepFOVMode := ckmHorizontalFOV;
  3958. end;
  3959. destructor TgxCamera.Destroy;
  3960. begin
  3961. TargetObject := nil;
  3962. inherited;
  3963. end;
  3964. procedure TgxCamera.Assign(Source: TPersistent);
  3965. var
  3966. cam: TgxCamera;
  3967. dir: TVector4f;
  3968. begin
  3969. if Assigned(Source) then
  3970. begin
  3971. inherited Assign(Source);
  3972. if Source is TgxCamera then
  3973. begin
  3974. cam := TgxCamera(Source);
  3975. SetDepthOfView(cam.DepthOfView);
  3976. SetFocalLength(cam.FocalLength);
  3977. SetCameraStyle(cam.CameraStyle);
  3978. SetSceneScale(cam.SceneScale);
  3979. SetNearPlaneBias(cam.NearPlaneBias);
  3980. SetScene(cam.Scene);
  3981. SetKeepFOVMode(cam.FKeepFOVMode);
  3982. if Parent <> nil then
  3983. begin
  3984. SetTargetObject(cam.TargetObject);
  3985. end
  3986. else // Design camera
  3987. begin
  3988. Position.AsVector := cam.AbsolutePosition;
  3989. if Assigned(cam.TargetObject) then
  3990. begin
  3991. VectorSubtract(cam.TargetObject.AbsolutePosition, AbsolutePosition, dir);
  3992. NormalizeVector(dir);
  3993. Direction.AsVector := dir;
  3994. end;
  3995. end;
  3996. end;
  3997. end;
  3998. end;
  3999. function TgxCamera.AbsoluteVectorToTarget: TVector4f;
  4000. begin
  4001. if TargetObject <> nil then
  4002. begin
  4003. VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition, Result);
  4004. NormalizeVector(Result);
  4005. end
  4006. else
  4007. Result := AbsoluteDirection;
  4008. end;
  4009. function TgxCamera.AbsoluteRightVectorToTarget: TVector4f;
  4010. begin
  4011. if TargetObject <> nil then
  4012. begin
  4013. VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition, Result);
  4014. Result := VectorCrossProduct(Result, AbsoluteUp);
  4015. NormalizeVector(Result);
  4016. end
  4017. else
  4018. Result := AbsoluteRight;
  4019. end;
  4020. function TgxCamera.AbsoluteUpVectorToTarget: TVector4f;
  4021. begin
  4022. if TargetObject <> nil then
  4023. Result := VectorCrossProduct(AbsoluteRightVectorToTarget, AbsoluteVectorToTarget)
  4024. else
  4025. Result := AbsoluteUp;
  4026. end;
  4027. // Apply
  4028. //
  4029. procedure TgxCamera.Apply;
  4030. var
  4031. v, d, v2: TVector4f;
  4032. absPos: TVector4f;
  4033. LM, mat: TMatrix4f;
  4034. begin
  4035. if Assigned(FDeferredApply) then
  4036. FDeferredApply(Self)
  4037. else
  4038. begin
  4039. if Assigned(FTargetObject) then
  4040. begin
  4041. v := TargetObject.AbsolutePosition;
  4042. absPos := AbsolutePosition;
  4043. VectorSubtract(v, absPos, d);
  4044. NormalizeVector(d);
  4045. FLastDirection := d;
  4046. LM := CreateLookAtMatrix(absPos, v, Up.AsVector);
  4047. end
  4048. else
  4049. begin
  4050. if Assigned(Parent) then
  4051. mat := Parent.AbsoluteMatrix
  4052. else
  4053. mat := IdentityHmgMatrix;
  4054. absPos := AbsolutePosition;
  4055. v := VectorTransform(Direction.AsVector, mat);
  4056. FLastDirection := v;
  4057. d := VectorTransform(Up.AsVector, mat);
  4058. v2 := VectorAdd(absPos, v);
  4059. LM := CreateLookAtMatrix(absPos, v2, d);
  4060. end;
  4061. with CurrentContext.PipeLineTransformation do
  4062. SetViewMatrix(MatrixMultiply(LM, ViewMatrix^));
  4063. ClearStructureChanged;
  4064. end;
  4065. end;
  4066. procedure TgxCamera.ApplyPerspective(const AViewport: TRectangle; AWidth, AHeight: Integer; ADPI: Integer);
  4067. var
  4068. vLeft, vRight, vBottom, vTop, vFar: Single;
  4069. MaxDim, ratio, f: Double;
  4070. xmax, ymax: Double;
  4071. mat: TMatrix4f;
  4072. const
  4073. cEpsilon: Single = 1E-4;
  4074. function IsPerspective(CamStyle: TgxCameraStyle): Boolean;
  4075. begin
  4076. Result := CamStyle in [csPerspective, csInfinitePerspective, csPerspectiveKeepFOV];
  4077. end;
  4078. begin
  4079. if (AWidth <= 0) or (AHeight <= 0) then
  4080. Exit;
  4081. if CameraStyle = csOrtho2D then
  4082. begin
  4083. vLeft := 0;
  4084. vRight := AWidth;
  4085. vBottom := 0;
  4086. vTop := AHeight;
  4087. FNearPlane := -1;
  4088. vFar := 1;
  4089. mat := CreateOrthoMatrix(vLeft, vRight, vBottom, vTop, FNearPlane, vFar);
  4090. with CurrentContext.PipeLineTransformation do
  4091. SetProjectionMatrix(MatrixMultiply(mat, ProjectionMatrix^));
  4092. FViewPortRadius := VectorLength(AWidth, AHeight) / 2;
  4093. end
  4094. else if CameraStyle = csCustom then
  4095. begin
  4096. FViewPortRadius := VectorLength(AWidth, AHeight) / 2;
  4097. if Assigned(FOnCustomPerspective) then
  4098. FOnCustomPerspective(AViewport, AWidth, AHeight, ADPI, FViewPortRadius);
  4099. end
  4100. else
  4101. begin
  4102. // determine biggest dimension and resolution (height or width)
  4103. MaxDim := AWidth;
  4104. if AHeight > MaxDim then
  4105. MaxDim := AHeight;
  4106. // calculate near plane distance and extensions;
  4107. // Scene ratio is determined by the window ratio. The viewport is just a
  4108. // specific part of the entire window and has therefore no influence on the
  4109. // scene ratio. What we need to know, though, is the ratio between the window
  4110. // borders (left, top, right and bottom) and the viewport borders.
  4111. // Note: viewport.top is actually bottom, because the window (and viewport) origin
  4112. // in OGL is the lower left corner
  4113. if IsPerspective(CameraStyle) then
  4114. f := FNearPlaneBias / (AWidth * FSceneScale)
  4115. else
  4116. f := 100 * FNearPlaneBias / (FocalLength * AWidth * FSceneScale);
  4117. // calculate window/viewport ratio for right extent
  4118. ratio := (2 * AViewport.width + 2 * AViewport.Left - AWidth) * f;
  4119. // calculate aspect ratio correct right value of the view frustum and take
  4120. // the window/viewport ratio also into account
  4121. vRight := ratio * AWidth / (2 * MaxDim);
  4122. // the same goes here for the other three extents
  4123. // left extent:
  4124. ratio := (AWidth - 2 * AViewport.Left) * f;
  4125. vLeft := -ratio * AWidth / (2 * MaxDim);
  4126. if IsPerspective(CameraStyle) then
  4127. f := FNearPlaneBias / (AHeight * FSceneScale)
  4128. else
  4129. f := 100 * FNearPlaneBias / (FocalLength * AHeight * FSceneScale);
  4130. // top extent (keep in mind the origin is left lower corner):
  4131. ratio := (2 * AViewport.height + 2 * AViewport.Top - AHeight) * f;
  4132. vTop := ratio * AHeight / (2 * MaxDim);
  4133. // bottom extent:
  4134. ratio := (AHeight - 2 * AViewport.Top) * f;
  4135. vBottom := -ratio * AHeight / (2 * MaxDim);
  4136. FNearPlane := FFocalLength * 2 * ADPI / (25.4 * MaxDim) * FNearPlaneBias;
  4137. vFar := FNearPlane + FDepthOfView;
  4138. // finally create view frustum (perspective or orthogonal)
  4139. case CameraStyle of
  4140. csPerspective:
  4141. begin
  4142. mat := CreateMatrixFromFrustum(vLeft, vRight, vBottom, vTop, FNearPlane, vFar);
  4143. end;
  4144. csPerspectiveKeepFOV:
  4145. begin
  4146. if FFOVY < 0 then // Need Update FOV
  4147. begin
  4148. FFOVY := ArcTan2(vTop - vBottom, 2 * FNearPlane) * 2;
  4149. FFOVX := ArcTan2(vRight - vLeft, 2 * FNearPlane) * 2;
  4150. end;
  4151. case FKeepFOVMode of
  4152. ckmVerticalFOV:
  4153. begin
  4154. ymax := FNearPlane * Tan(FFOVY / 2);
  4155. xmax := ymax * AWidth / AHeight;
  4156. end;
  4157. ckmHorizontalFOV:
  4158. begin
  4159. xmax := FNearPlane * Tan(FFOVX / 2);
  4160. ymax := xmax * AHeight / AWidth;
  4161. end;
  4162. else
  4163. begin
  4164. xmax := 0;
  4165. ymax := 0;
  4166. Assert(False, 'Unknown keep camera angle mode');
  4167. end;
  4168. end;
  4169. mat := CreateMatrixFromFrustum(-xmax, xmax, -ymax, ymax, FNearPlane, vFar);
  4170. end;
  4171. csInfinitePerspective:
  4172. begin
  4173. mat := IdentityHmgMatrix;
  4174. mat.x.x := 2 * FNearPlane / (vRight - vLeft);
  4175. mat.y.y := 2 * FNearPlane / (vTop - vBottom);
  4176. mat.z.x := (vRight + vLeft) / (vRight - vLeft);
  4177. mat.z.y := (vTop + vBottom) / (vTop - vBottom);
  4178. mat.z.z := cEpsilon - 1;
  4179. mat.z.W := -1;
  4180. mat.W.z := FNearPlane * (cEpsilon - 2);
  4181. mat.W.W := 0;
  4182. end;
  4183. csOrthogonal:
  4184. begin
  4185. mat := CreateOrthoMatrix(vLeft, vRight, vBottom, vTop, FNearPlane, vFar);
  4186. end;
  4187. else
  4188. Assert(False);
  4189. end;
  4190. with CurrentContext.PipeLineTransformation do
  4191. SetProjectionMatrix(MatrixMultiply(mat, ProjectionMatrix^));
  4192. FViewPortRadius := VectorLength(vRight, vTop) / FNearPlane
  4193. end;
  4194. end;
  4195. // ------------------------------------------------------------------------------
  4196. procedure TgxCamera.AutoLeveling(Factor: Single);
  4197. var
  4198. rightVector, rotAxis: TVector4f;
  4199. angle: Single;
  4200. begin
  4201. angle := RadianToDeg(ArcCosine(VectorDotProduct(FUp.AsVector, YVector)));
  4202. rotAxis := VectorCrossProduct(YHmgVector, FUp.AsVector);
  4203. if (angle > 1) and (VectorLength(rotAxis) > 0) then
  4204. begin
  4205. rightVector := VectorCrossProduct(FDirection.AsVector, FUp.AsVector);
  4206. FUp.Rotate(AffineVectorMake(rotAxis), angle / (10 * Factor));
  4207. FUp.Normalize;
  4208. // adjust local coordinates
  4209. FDirection.DirectVector := VectorCrossProduct(FUp.AsVector, rightVector);
  4210. FRotation.z := -RadToDeg(ArcTan2(rightVector.y, VectorLength(rightVector.x, rightVector.z)));
  4211. end;
  4212. end;
  4213. // ------------------------------------------------------------------------------
  4214. procedure TgxCamera.Notification(AComponent: TComponent; Operation: TOperation);
  4215. begin
  4216. if (Operation = opRemove) and (AComponent = FTargetObject) then
  4217. TargetObject := nil;
  4218. inherited;
  4219. end;
  4220. procedure TgxCamera.SetTargetObject(const val: TgxBaseSceneObject);
  4221. begin
  4222. if (FTargetObject <> val) then
  4223. begin
  4224. if Assigned(FTargetObject) then
  4225. FTargetObject.RemoveFreeNotification(Self);
  4226. FTargetObject := val;
  4227. if Assigned(FTargetObject) then
  4228. FTargetObject.FreeNotification(Self);
  4229. if not(csLoading in ComponentState) then
  4230. TransformationChanged;
  4231. end;
  4232. end;
  4233. procedure TgxCamera.Reset(aSceneBuffer: TgxSceneBuffer);
  4234. var
  4235. Extent: Single;
  4236. begin
  4237. FRotation.z := 0;
  4238. FFocalLength := 50;
  4239. with aSceneBuffer do
  4240. begin
  4241. ApplyPerspective(FViewPort, FViewPort.width, FViewPort.height, FRenderDPI);
  4242. FUp.DirectVector := YHmgVector;
  4243. if FViewPort.height < FViewPort.width then
  4244. Extent := FViewPort.height * 0.25
  4245. else
  4246. Extent := FViewPort.width * 0.25;
  4247. end;
  4248. FPosition.SetPoint(0, 0, FNearPlane * Extent);
  4249. FDirection.SetVector(0, 0, -1, 0);
  4250. TransformationChanged;
  4251. end;
  4252. procedure TgxCamera.ZoomAll(aSceneBuffer: TgxSceneBuffer);
  4253. var
  4254. Extent: Single;
  4255. begin
  4256. with aSceneBuffer do
  4257. begin
  4258. if FViewPort.height < FViewPort.width then
  4259. Extent := FViewPort.height * 0.25
  4260. else
  4261. Extent := FViewPort.width * 0.25;
  4262. FPosition.DirectVector := NullHmgPoint;
  4263. Move(-FNearPlane * Extent);
  4264. // let the camera look at the scene center
  4265. FDirection.SetVector(-FPosition.x, -FPosition.y, -FPosition.z, 0);
  4266. end;
  4267. end;
  4268. procedure TgxCamera.RotateObject(obj: TgxBaseSceneObject; pitchDelta, turnDelta: Single; rollDelta: Single = 0);
  4269. var
  4270. resMat: TMatrix4f;
  4271. vDir, vUp, vRight: TVector4f;
  4272. v: TAffineVector;
  4273. position1: TVector4f;
  4274. Scale1: TVector4f;
  4275. begin
  4276. // First we need to compute the actual camera's vectors, which may not be
  4277. // directly available if we're in "targeting" mode
  4278. vUp := AbsoluteUp;
  4279. if TargetObject <> nil then
  4280. begin
  4281. vDir := AbsoluteVectorToTarget;
  4282. vRight := VectorCrossProduct(vDir, vUp);
  4283. vUp := VectorCrossProduct(vRight, vDir);
  4284. end
  4285. else
  4286. begin
  4287. vDir := AbsoluteDirection;
  4288. vRight := VectorCrossProduct(vDir, vUp);
  4289. end;
  4290. // save scale & position info
  4291. Scale1 := obj.Scale.AsVector;
  4292. position1 := obj.Position.AsVector;
  4293. resMat := obj.Matrix^;
  4294. // get rid of scaling & location info
  4295. NormalizeMatrix(resMat);
  4296. // Now we build rotation matrices and use them to rotate the obj
  4297. if rollDelta <> 0 then
  4298. begin
  4299. SetVector(v, obj.AbsoluteToLocal(vDir));
  4300. resMat := MatrixMultiply(CreateRotationMatrix(v, DegToRadian(rollDelta)), resMat);
  4301. end;
  4302. if turnDelta <> 0 then
  4303. begin
  4304. SetVector(v, obj.AbsoluteToLocal(vUp));
  4305. resMat := MatrixMultiply(CreateRotationMatrix(v, DegToRadian(turnDelta)), resMat);
  4306. end;
  4307. if pitchDelta <> 0 then
  4308. begin
  4309. SetVector(v, obj.AbsoluteToLocal(vRight));
  4310. resMat := MatrixMultiply(CreateRotationMatrix(v, DegToRadian(pitchDelta)), resMat);
  4311. end;
  4312. obj.SetMatrix(resMat);
  4313. // restore scaling & rotation info
  4314. obj.Scale.AsVector := Scale1;
  4315. obj.Position.AsVector := position1;
  4316. end;
  4317. procedure TgxCamera.RotateTarget(pitchDelta, turnDelta: Single; rollDelta: Single = 0);
  4318. begin
  4319. if Assigned(FTargetObject) then
  4320. RotateObject(FTargetObject, pitchDelta, turnDelta, rollDelta)
  4321. end;
  4322. procedure TgxCamera.MoveAroundTarget(pitchDelta, turnDelta: Single);
  4323. begin
  4324. MoveObjectAround(FTargetObject, pitchDelta, turnDelta);
  4325. end;
  4326. procedure TgxCamera.MoveAllAroundTarget(pitchDelta, turnDelta: Single);
  4327. begin
  4328. MoveObjectAllAround(FTargetObject, pitchDelta, turnDelta);
  4329. end;
  4330. procedure TgxCamera.MoveInEyeSpace(forwardDistance, rightDistance, upDistance: Single);
  4331. var
  4332. trVector: TVector4f;
  4333. begin
  4334. trVector := AbsoluteEyeSpaceVector(forwardDistance, rightDistance, upDistance);
  4335. if Assigned(Parent) then
  4336. Position.Translate(Parent.AbsoluteToLocal(trVector))
  4337. else
  4338. Position.Translate(trVector);
  4339. end;
  4340. procedure TgxCamera.MoveTargetInEyeSpace(forwardDistance, rightDistance, upDistance: Single);
  4341. var
  4342. trVector: TVector4f;
  4343. begin
  4344. if TargetObject <> nil then
  4345. begin
  4346. trVector := AbsoluteEyeSpaceVector(forwardDistance, rightDistance, upDistance);
  4347. TargetObject.Position.Translate(TargetObject.Parent.AbsoluteToLocal(trVector));
  4348. end;
  4349. end;
  4350. function TgxCamera.AbsoluteEyeSpaceVector(forwardDistance, rightDistance, upDistance: Single): TVector4f;
  4351. begin
  4352. Result := NullHmgVector;
  4353. if forwardDistance <> 0 then
  4354. CombineVector(Result, AbsoluteVectorToTarget, forwardDistance);
  4355. if rightDistance <> 0 then
  4356. CombineVector(Result, AbsoluteRightVectorToTarget, rightDistance);
  4357. if upDistance <> 0 then
  4358. CombineVector(Result, AbsoluteUpVectorToTarget, upDistance);
  4359. end;
  4360. procedure TgxCamera.AdjustDistanceToTarget(distanceRatio: Single);
  4361. var
  4362. vect: TVector4f;
  4363. begin
  4364. if Assigned(FTargetObject) then
  4365. begin
  4366. // calculate vector from target to camera in absolute coordinates
  4367. vect := VectorSubtract(AbsolutePosition, TargetObject.AbsolutePosition);
  4368. // ratio -> translation vector
  4369. ScaleVector(vect, -(1 - distanceRatio));
  4370. AddVector(vect, AbsolutePosition);
  4371. if Assigned(Parent) then
  4372. vect := Parent.AbsoluteToLocal(vect);
  4373. Position.AsVector := vect;
  4374. end;
  4375. end;
  4376. function TgxCamera.DistanceToTarget: Single;
  4377. var
  4378. vect: TVector4f;
  4379. begin
  4380. if Assigned(FTargetObject) then
  4381. begin
  4382. vect := VectorSubtract(AbsolutePosition, TargetObject.AbsolutePosition);
  4383. Result := VectorLength(vect);
  4384. end
  4385. else
  4386. Result := 1;
  4387. end;
  4388. function TgxCamera.ScreenDeltaToVector(deltaX, deltaY: Integer; ratio: Single; const planeNormal: TVector4f): TVector4f;
  4389. var
  4390. screenY, screenX: TVector4f;
  4391. screenYoutOfPlaneComponent: Single;
  4392. begin
  4393. // calculate projection of direction vector on the plane
  4394. if Assigned(FTargetObject) then
  4395. screenY := VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition)
  4396. else
  4397. screenY := Direction.AsVector;
  4398. screenYoutOfPlaneComponent := VectorDotProduct(screenY, planeNormal);
  4399. screenY := VectorCombine(screenY, planeNormal, 1, -screenYoutOfPlaneComponent);
  4400. NormalizeVector(screenY);
  4401. // calc the screenX vector
  4402. screenX := VectorCrossProduct(screenY, planeNormal);
  4403. // and here, we're done
  4404. Result := VectorCombine(screenX, screenY, deltaX * ratio, deltaY * ratio);
  4405. end;
  4406. function TgxCamera.ScreenDeltaToVectorXY(deltaX, deltaY: Integer; ratio: Single): TVector4f;
  4407. var
  4408. screenY: TVector4f;
  4409. dxr, dyr, d: Single;
  4410. begin
  4411. // calculate projection of direction vector on the plane
  4412. if Assigned(FTargetObject) then
  4413. screenY := VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition)
  4414. else
  4415. screenY := Direction.AsVector;
  4416. d := VectorLength(screenY.x, screenY.y);
  4417. if d <= 1E-10 then
  4418. d := ratio
  4419. else
  4420. d := ratio / d;
  4421. // and here, we're done
  4422. dxr := deltaX * d;
  4423. dyr := deltaY * d;
  4424. Result.x := screenY.y * dxr + screenY.x * dyr;
  4425. Result.y := screenY.y * dyr - screenY.x * dxr;
  4426. Result.z := 0;
  4427. Result.W := 0;
  4428. end;
  4429. function TgxCamera.ScreenDeltaToVectorXZ(deltaX, deltaY: Integer; ratio: Single): TVector4f;
  4430. var
  4431. screenY: TVector4f;
  4432. d, dxr, dzr: Single;
  4433. begin
  4434. // calculate the projection of direction vector on the plane
  4435. if Assigned(FTargetObject) then
  4436. screenY := VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition)
  4437. else
  4438. screenY := Direction.AsVector;
  4439. d := VectorLength(screenY.x, screenY.z);
  4440. if d <= 1E-10 then
  4441. d := ratio
  4442. else
  4443. d := ratio / d;
  4444. dxr := deltaX * d;
  4445. dzr := deltaY * d;
  4446. Result.x := -screenY.z * dxr + screenY.x * dzr;
  4447. Result.y := 0;
  4448. Result.z := screenY.z * dzr + screenY.x * dxr;
  4449. Result.W := 0;
  4450. end;
  4451. function TgxCamera.ScreenDeltaToVectorYZ(deltaX, deltaY: Integer; ratio: Single): TVector4f;
  4452. var
  4453. screenY: TVector4f;
  4454. d, dyr, dzr: Single;
  4455. begin
  4456. // calculate the projection of direction vector on the plane
  4457. if Assigned(FTargetObject) then
  4458. screenY := VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition)
  4459. else
  4460. screenY := Direction.AsVector;
  4461. d := VectorLength(screenY.y, screenY.z);
  4462. if d <= 1E-10 then
  4463. d := ratio
  4464. else
  4465. d := ratio / d;
  4466. dyr := deltaX * d;
  4467. dzr := deltaY * d;
  4468. Result.x := 0;
  4469. Result.y := screenY.z * dyr + screenY.y * dzr;
  4470. Result.z := screenY.z * dzr - screenY.y * dyr;
  4471. Result.W := 0;
  4472. end;
  4473. function TgxCamera.PointInFront(const point: TVector4f): Boolean;
  4474. begin
  4475. Result := PointIsInHalfSpace(point, AbsolutePosition, AbsoluteDirection);
  4476. end;
  4477. procedure TgxCamera.SetDepthOfView(aValue: Single);
  4478. begin
  4479. if FDepthOfView <> aValue then
  4480. begin
  4481. FDepthOfView := aValue;
  4482. FFOVY := -1;
  4483. if not(csLoading in ComponentState) then
  4484. TransformationChanged;
  4485. end;
  4486. end;
  4487. procedure TgxCamera.SetFocalLength(aValue: Single);
  4488. begin
  4489. if aValue <= 0 then
  4490. aValue := 1;
  4491. if FFocalLength <> aValue then
  4492. begin
  4493. FFocalLength := aValue;
  4494. FFOVY := -1;
  4495. if not(csLoading in ComponentState) then
  4496. TransformationChanged;
  4497. end;
  4498. end;
  4499. function TgxCamera.GetFieldOfView(const AViewportDimension: Single): Single;
  4500. begin
  4501. if FFocalLength = 0 then
  4502. Result := 0
  4503. else
  4504. Result := RadToDeg(2 * ArcTan2(AViewportDimension * 0.5, FFocalLength));
  4505. end;
  4506. procedure TgxCamera.SetFieldOfView(const AFieldOfView, AViewportDimension: Single);
  4507. begin
  4508. FocalLength := AViewportDimension / (2 * Tan(DegToRadian(AFieldOfView / 2)));
  4509. end;
  4510. procedure TgxCamera.SetCameraStyle(const val: TgxCameraStyle);
  4511. begin
  4512. if FCameraStyle <> val then
  4513. begin
  4514. FCameraStyle := val;
  4515. FFOVY := -1;
  4516. NotifyChange(Self);
  4517. end;
  4518. end;
  4519. procedure TgxCamera.SetKeepFOVMode(const val: TgxCameraKeepFOVMode);
  4520. begin
  4521. if FKeepFOVMode <> val then
  4522. begin
  4523. FKeepFOVMode := val;
  4524. FFOVY := -1;
  4525. if FCameraStyle = csPerspectiveKeepFOV then
  4526. NotifyChange(Self);
  4527. end;
  4528. end;
  4529. procedure TgxCamera.SetSceneScale(Value: Single);
  4530. begin
  4531. if Value = 0 then
  4532. Value := 1;
  4533. if FSceneScale <> Value then
  4534. begin
  4535. FSceneScale := Value;
  4536. FFOVY := -1;
  4537. NotifyChange(Self);
  4538. end;
  4539. end;
  4540. function TgxCamera.StoreSceneScale: Boolean;
  4541. begin
  4542. Result := (FSceneScale <> 1);
  4543. end;
  4544. procedure TgxCamera.SetNearPlaneBias(Value: Single);
  4545. begin
  4546. if Value <= 0 then
  4547. Value := 1;
  4548. if FNearPlaneBias <> Value then
  4549. begin
  4550. FNearPlaneBias := Value;
  4551. FFOVY := -1;
  4552. NotifyChange(Self);
  4553. end;
  4554. end;
  4555. function TgxCamera.StoreNearPlaneBias: Boolean;
  4556. begin
  4557. Result := (FNearPlaneBias <> 1);
  4558. end;
  4559. procedure TgxCamera.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
  4560. begin
  4561. if ARenderChildren and (Count > 0) then
  4562. Self.RenderChildren(0, Count - 1, ARci);
  4563. end;
  4564. function TgxCamera.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
  4565. intersectNormal: PVector4f = nil): Boolean;
  4566. begin
  4567. Result := False;
  4568. end;
  4569. // ------------------
  4570. // ------------------ TgxImmaterialSceneObject ------------------
  4571. // ------------------
  4572. procedure TgxImmaterialSceneObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
  4573. begin
  4574. // start rendering self
  4575. if ARenderSelf then
  4576. begin
  4577. if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
  4578. BuildList(ARci)
  4579. else
  4580. ARci.gxStates.CallList(GetHandle(ARci));
  4581. end;
  4582. // start rendering children (if any)
  4583. if ARenderChildren then
  4584. Self.RenderChildren(0, Count - 1, ARci);
  4585. end;
  4586. // ------------------
  4587. // ------------------ TgxCameraInvariantObject ------------------
  4588. // ------------------
  4589. constructor TgxCameraInvariantObject.Create(AOwner: TComponent);
  4590. begin
  4591. inherited;
  4592. FCamInvarianceMode := cimNone;
  4593. end;
  4594. procedure TgxCameraInvariantObject.Assign(Source: TPersistent);
  4595. begin
  4596. if Source is TgxCameraInvariantObject then
  4597. begin
  4598. FCamInvarianceMode := TgxCameraInvariantObject(Source).FCamInvarianceMode;
  4599. end;
  4600. inherited Assign(Source);
  4601. end;
  4602. procedure TgxCameraInvariantObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
  4603. begin
  4604. if CamInvarianceMode <> cimNone then
  4605. with ARci.PipeLineTransformation do
  4606. begin
  4607. Push;
  4608. // try
  4609. // prepare
  4610. case CamInvarianceMode of
  4611. cimPosition:
  4612. begin
  4613. SetViewMatrix(MatrixMultiply(CreateTranslationMatrix(ARci.cameraPosition),
  4614. ARci.PipeLineTransformation.ViewMatrix^));
  4615. end;
  4616. cimOrientation:
  4617. begin
  4618. // makes the coordinates system more 'intuitive' (Z+ forward)
  4619. SetViewMatrix(CreateScaleMatrix(Vector3fMake(1, -1, -1)))
  4620. end;
  4621. else
  4622. Assert(False);
  4623. end;
  4624. // Apply local transform
  4625. SetModelMatrix(LocalMatrix^);
  4626. if ARenderSelf then
  4627. begin
  4628. if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
  4629. BuildList(ARci)
  4630. else
  4631. ARci.gxStates.CallList(GetHandle(ARci));
  4632. end;
  4633. if ARenderChildren then
  4634. Self.RenderChildren(0, Count - 1, ARci);
  4635. // finally
  4636. Pop;
  4637. // end;
  4638. end
  4639. else
  4640. inherited;
  4641. end;
  4642. procedure TgxCameraInvariantObject.SetCamInvarianceMode(const val: TgxCameraInvarianceMode);
  4643. begin
  4644. if FCamInvarianceMode <> val then
  4645. begin
  4646. FCamInvarianceMode := val;
  4647. NotifyChange(Self);
  4648. end;
  4649. end;
  4650. // ------------------
  4651. // ------------------ TxDirectOpenGL ------------------
  4652. // ------------------
  4653. constructor TgxDirectOpenGL.Create(AOwner: TComponent);
  4654. begin
  4655. inherited;
  4656. ObjectStyle := ObjectStyle + [osDirectDraw];
  4657. FBlend := False;
  4658. end;
  4659. procedure TgxDirectOpenGL.Assign(Source: TPersistent);
  4660. begin
  4661. if Source is TgxDirectOpenGL then
  4662. begin
  4663. UseBuildList := TgxDirectOpenGL(Source).UseBuildList;
  4664. FOnRender := TgxDirectOpenGL(Source).FOnRender;
  4665. FBlend := TgxDirectOpenGL(Source).Blend;
  4666. end;
  4667. inherited Assign(Source);
  4668. end;
  4669. procedure TgxDirectOpenGL.BuildList(var rci: TgxRenderContextInfo);
  4670. begin
  4671. if Assigned(FOnRender) then
  4672. begin
  4673. xglMapTexCoordToMain; // single texturing by default
  4674. OnRender(Self, rci);
  4675. end;
  4676. end;
  4677. function TgxDirectOpenGL.AxisAlignedDimensionsUnscaled: TVector4f;
  4678. begin
  4679. Result := NullHmgPoint;
  4680. end;
  4681. procedure TgxDirectOpenGL.SetUseBuildList(const val: Boolean);
  4682. begin
  4683. if val <> FUseBuildList then
  4684. begin
  4685. FUseBuildList := val;
  4686. if val then
  4687. ObjectStyle := ObjectStyle - [osDirectDraw]
  4688. else
  4689. ObjectStyle := ObjectStyle + [osDirectDraw];
  4690. end;
  4691. end;
  4692. function TgxDirectOpenGL.Blended: Boolean;
  4693. begin
  4694. Result := FBlend;
  4695. end;
  4696. procedure TgxDirectOpenGL.SetBlend(const val: Boolean);
  4697. begin
  4698. if val <> FBlend then
  4699. begin
  4700. FBlend := val;
  4701. StructureChanged;
  4702. end;
  4703. end;
  4704. // ------------------
  4705. // ------------------ TgxRenderPoint ------------------
  4706. // ------------------
  4707. constructor TgxRenderPoint.Create(AOwner: TComponent);
  4708. begin
  4709. inherited;
  4710. ObjectStyle := ObjectStyle + [osDirectDraw];
  4711. end;
  4712. destructor TgxRenderPoint.Destroy;
  4713. begin
  4714. Clear;
  4715. inherited;
  4716. end;
  4717. procedure TgxRenderPoint.BuildList(var rci: TgxRenderContextInfo);
  4718. var
  4719. i: Integer;
  4720. begin
  4721. for i := 0 to High(FCallBacks) do
  4722. FCallBacks[i](Self, rci);
  4723. end;
  4724. procedure TgxRenderPoint.RegisterCallBack(renderEvent: TDirectRenderEvent; renderPointFreed: TNotifyEvent);
  4725. var
  4726. n: Integer;
  4727. begin
  4728. n := Length(FCallBacks);
  4729. SetLength(FCallBacks, n + 1);
  4730. SetLength(FFreeCallBacks, n + 1);
  4731. FCallBacks[n] := renderEvent;
  4732. FFreeCallBacks[n] := renderPointFreed;
  4733. end;
  4734. procedure TgxRenderPoint.UnRegisterCallBack(renderEvent: TDirectRenderEvent);
  4735. type
  4736. TEventContainer = record
  4737. event: TDirectRenderEvent;
  4738. end;
  4739. var
  4740. i, j, n: Integer;
  4741. refContainer, listContainer: TEventContainer;
  4742. begin
  4743. refContainer.event := renderEvent;
  4744. n := Length(FCallBacks);
  4745. for i := 0 to n - 1 do
  4746. begin
  4747. listContainer.event := FCallBacks[i];
  4748. if CompareMem(@listContainer, @refContainer, SizeOf(TEventContainer)) then
  4749. begin
  4750. for j := i + 1 to n - 1 do
  4751. begin
  4752. FCallBacks[j - 1] := FCallBacks[j];
  4753. FFreeCallBacks[j - 1] := FFreeCallBacks[j];
  4754. end;
  4755. SetLength(FCallBacks, n - 1);
  4756. SetLength(FFreeCallBacks, n - 1);
  4757. Break;
  4758. end;
  4759. end;
  4760. end;
  4761. procedure TgxRenderPoint.Clear;
  4762. begin
  4763. while Length(FCallBacks) > 0 do
  4764. begin
  4765. FFreeCallBacks[High(FCallBacks)](Self);
  4766. SetLength(FCallBacks, Length(FCallBacks) - 1);
  4767. end;
  4768. end;
  4769. // ------------------
  4770. // ------------------ TgxProxyObject ------------------
  4771. // ------------------
  4772. constructor TgxProxyObject.Create(AOwner: TComponent);
  4773. begin
  4774. inherited;
  4775. FProxyOptions := cDefaultProxyOptions;
  4776. end;
  4777. destructor TgxProxyObject.Destroy;
  4778. begin
  4779. SetMasterObject(nil);
  4780. inherited;
  4781. end;
  4782. procedure TgxProxyObject.Assign(Source: TPersistent);
  4783. begin
  4784. if Source is TgxProxyObject then
  4785. begin
  4786. SetMasterObject(TgxProxyObject(Source).MasterObject);
  4787. end;
  4788. inherited Assign(Source);
  4789. end;
  4790. procedure TgxProxyObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
  4791. var
  4792. gotMaster, masterGotEffects, oldProxySubObject: Boolean;
  4793. begin
  4794. if FRendering then
  4795. Exit;
  4796. FRendering := True;
  4797. try
  4798. gotMaster := Assigned(FMasterObject);
  4799. masterGotEffects := gotMaster and (pooEffects in FProxyOptions) and (FMasterObject.Effects.Count > 0);
  4800. if gotMaster then
  4801. begin
  4802. if pooObjects in FProxyOptions then
  4803. begin
  4804. oldProxySubObject := ARci.proxySubObject;
  4805. ARci.proxySubObject := True;
  4806. if pooTransformation in FProxyOptions then
  4807. with ARci.PipeLineTransformation do
  4808. SetModelMatrix(MatrixMultiply(FMasterObject.Matrix^, ModelMatrix^));
  4809. FMasterObject.DoRender(ARci, ARenderSelf, (FMasterObject.Count > 0));
  4810. ARci.proxySubObject := oldProxySubObject;
  4811. end;
  4812. end;
  4813. // now render self stuff (our children, our effects, etc.)
  4814. if ARenderChildren and (Count > 0) then
  4815. Self.RenderChildren(0, Count - 1, ARci);
  4816. if masterGotEffects then
  4817. FMasterObject.Effects.RenderPostEffects(ARci);
  4818. finally
  4819. FRendering := False;
  4820. end;
  4821. ClearStructureChanged;
  4822. end;
  4823. function TgxProxyObject.AxisAlignedDimensions: TVector4f;
  4824. begin
  4825. If Assigned(FMasterObject) then
  4826. begin
  4827. Result := FMasterObject.AxisAlignedDimensionsUnscaled;
  4828. If (pooTransformation in ProxyOptions) then
  4829. ScaleVector(Result, FMasterObject.Scale.AsVector)
  4830. else
  4831. ScaleVector(Result, Scale.AsVector);
  4832. end
  4833. else
  4834. Result := inherited AxisAlignedDimensions;
  4835. end;
  4836. function TgxProxyObject.AxisAlignedDimensionsUnscaled: TVector4f;
  4837. begin
  4838. if Assigned(FMasterObject) then
  4839. begin
  4840. Result := FMasterObject.AxisAlignedDimensionsUnscaled;
  4841. end
  4842. else
  4843. Result := inherited AxisAlignedDimensionsUnscaled;
  4844. end;
  4845. function TgxProxyObject.BarycenterAbsolutePosition: TVector4f;
  4846. var
  4847. lAdjustVector: TVector4f;
  4848. begin
  4849. if Assigned(FMasterObject) then
  4850. begin
  4851. // Not entirely correct, but better than nothing...
  4852. lAdjustVector := VectorSubtract(FMasterObject.BarycenterAbsolutePosition, FMasterObject.AbsolutePosition);
  4853. Position.AsVector := VectorAdd(Position.AsVector, lAdjustVector);
  4854. Result := AbsolutePosition;
  4855. Position.AsVector := VectorSubtract(Position.AsVector, lAdjustVector);
  4856. end
  4857. else
  4858. Result := inherited BarycenterAbsolutePosition;
  4859. end;
  4860. procedure TgxProxyObject.Notification(AComponent: TComponent; Operation: TOperation);
  4861. begin
  4862. if (Operation = opRemove) and (AComponent = FMasterObject) then
  4863. MasterObject := nil;
  4864. inherited;
  4865. end;
  4866. procedure TgxProxyObject.SetMasterObject(const val: TgxBaseSceneObject);
  4867. begin
  4868. if FMasterObject <> val then
  4869. begin
  4870. if Assigned(FMasterObject) then
  4871. FMasterObject.RemoveFreeNotification(Self);
  4872. FMasterObject := val;
  4873. if Assigned(FMasterObject) then
  4874. FMasterObject.FreeNotification(Self);
  4875. StructureChanged;
  4876. end;
  4877. end;
  4878. procedure TgxProxyObject.SetProxyOptions(const val: TgxProxyObjectOptions);
  4879. begin
  4880. if FProxyOptions <> val then
  4881. begin
  4882. FProxyOptions := val;
  4883. StructureChanged;
  4884. end;
  4885. end;
  4886. function TgxProxyObject.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
  4887. intersectNormal: PVector4f = nil): Boolean;
  4888. var
  4889. localRayStart, localRayVector: TVector4f;
  4890. begin
  4891. if Assigned(MasterObject) then
  4892. begin
  4893. SetVector(localRayStart, AbsoluteToLocal(rayStart));
  4894. SetVector(localRayStart, MasterObject.LocalToAbsolute(localRayStart));
  4895. SetVector(localRayVector, AbsoluteToLocal(rayVector));
  4896. SetVector(localRayVector, MasterObject.LocalToAbsolute(localRayVector));
  4897. NormalizeVector(localRayVector);
  4898. Result := MasterObject.RayCastIntersect(localRayStart, localRayVector, intersectPoint, intersectNormal);
  4899. if Result then
  4900. begin
  4901. if Assigned(intersectPoint) then
  4902. begin
  4903. SetVector(intersectPoint^, MasterObject.AbsoluteToLocal(intersectPoint^));
  4904. SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
  4905. end;
  4906. if Assigned(intersectNormal) then
  4907. begin
  4908. SetVector(intersectNormal^, MasterObject.AbsoluteToLocal(intersectNormal^));
  4909. SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
  4910. end;
  4911. end;
  4912. end
  4913. else
  4914. Result := False;
  4915. end;
  4916. function TgxProxyObject.GenerateSilhouette(const silhouetteParameters: TgxSilhouetteParameters): TgxSilhouette;
  4917. begin
  4918. if Assigned(MasterObject) then
  4919. Result := MasterObject.GenerateSilhouette(silhouetteParameters)
  4920. else
  4921. Result := nil;
  4922. end;
  4923. // ------------------
  4924. // ------------------ TxLightSource ------------------
  4925. // ------------------
  4926. constructor TgxLightSource.Create(AOwner: TComponent);
  4927. begin
  4928. inherited Create(AOwner);
  4929. FListHandle := nil;
  4930. FShining := True;
  4931. FSpotDirection := TgxCoordinates.CreateInitialized(Self, VectorMake(0, 0, -1, 0), csVector);
  4932. FConstAttenuation := 1;
  4933. FLinearAttenuation := 0;
  4934. FQuadraticAttenuation := 0;
  4935. FSpotCutOff := 180;
  4936. FSpotExponent := 0;
  4937. FLightStyle := lsSpot;
  4938. FAmbient := TgxColor.Create(Self);
  4939. FDiffuse := TgxColor.Create(Self);
  4940. FDiffuse.Initialize(clrWhite);
  4941. FSpecular := TgxColor.Create(Self);
  4942. end;
  4943. destructor TgxLightSource.Destroy;
  4944. begin
  4945. FSpotDirection.Free;
  4946. FAmbient.Free;
  4947. FDiffuse.Free;
  4948. FSpecular.Free;
  4949. inherited Destroy;
  4950. end;
  4951. procedure TgxLightSource.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
  4952. begin
  4953. if ARenderChildren and Assigned(FChildren) then
  4954. Self.RenderChildren(0, Count - 1, ARci);
  4955. end;
  4956. function TgxLightSource.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
  4957. intersectNormal: PVector4f = nil): Boolean;
  4958. begin
  4959. Result := False;
  4960. end;
  4961. procedure TgxLightSource.CoordinateChanged(Sender: TgxCustomCoordinates);
  4962. begin
  4963. inherited;
  4964. if Sender = FSpotDirection then
  4965. TransformationChanged;
  4966. end;
  4967. function TgxLightSource.GenerateSilhouette(const SilhouetteParameters: TgxSilhouetteParameters): TgxSilhouette;
  4968. begin
  4969. Result := nil;
  4970. end;
  4971. procedure TgxLightSource.SetShining(aValue: Boolean);
  4972. begin
  4973. if aValue <> FShining then
  4974. begin
  4975. FShining := aValue;
  4976. NotifyChange(Self);
  4977. end;
  4978. end;
  4979. procedure TgxLightSource.SetSpotDirection(AVector: TgxCoordinates);
  4980. begin
  4981. FSpotDirection.DirectVector := AVector.AsVector;
  4982. FSpotDirection.W := 0;
  4983. NotifyChange(Self);
  4984. end;
  4985. procedure TgxLightSource.SetSpotExponent(aValue: Single);
  4986. begin
  4987. if FSpotExponent <> aValue then
  4988. begin
  4989. FSpotExponent := aValue;
  4990. NotifyChange(Self);
  4991. end;
  4992. end;
  4993. procedure TgxLightSource.SetSpotCutOff(const val: Single);
  4994. begin
  4995. if FSpotCutOff <> val then
  4996. begin
  4997. if ((val >= 0) and (val <= 90)) or (val = 180) then
  4998. begin
  4999. FSpotCutOff := val;
  5000. NotifyChange(Self);
  5001. end;
  5002. end;
  5003. end;
  5004. procedure TgxLightSource.SetLightStyle(const val: TgxLightStyle);
  5005. begin
  5006. if FLightStyle <> val then
  5007. begin
  5008. FLightStyle := val;
  5009. NotifyChange(Self);
  5010. end;
  5011. end;
  5012. procedure TgxLightSource.SetAmbient(aValue: TgxColor);
  5013. begin
  5014. FAmbient.Color := aValue.Color;
  5015. NotifyChange(Self);
  5016. end;
  5017. procedure TgxLightSource.SetDiffuse(aValue: TgxColor);
  5018. begin
  5019. FDiffuse.Color := aValue.Color;
  5020. NotifyChange(Self);
  5021. end;
  5022. procedure TgxLightSource.SetSpecular(aValue: TgxColor);
  5023. begin
  5024. FSpecular.Color := aValue.Color;
  5025. NotifyChange(Self);
  5026. end;
  5027. procedure TgxLightSource.SetConstAttenuation(aValue: Single);
  5028. begin
  5029. if FConstAttenuation <> aValue then
  5030. begin
  5031. FConstAttenuation := aValue;
  5032. NotifyChange(Self);
  5033. end;
  5034. end;
  5035. procedure TgxLightSource.SetLinearAttenuation(aValue: Single);
  5036. begin
  5037. if FLinearAttenuation <> aValue then
  5038. begin
  5039. FLinearAttenuation := aValue;
  5040. NotifyChange(Self);
  5041. end;
  5042. end;
  5043. procedure TgxLightSource.SetQuadraticAttenuation(aValue: Single);
  5044. begin
  5045. if FQuadraticAttenuation <> aValue then
  5046. begin
  5047. FQuadraticAttenuation := aValue;
  5048. NotifyChange(Self);
  5049. end;
  5050. end;
  5051. function TgxLightSource.Attenuated: Boolean;
  5052. begin
  5053. Result := (LightStyle <> lsParallel) and ((ConstAttenuation <> 1) or (LinearAttenuation <> 0) or (QuadraticAttenuation <> 0));
  5054. end;
  5055. // ------------------
  5056. // ------------------ TgxScene ------------------
  5057. // ------------------
  5058. constructor TgxScene.Create(AOwner: TComponent);
  5059. begin
  5060. inherited;
  5061. // root creation
  5062. FCurrentBuffer := nil;
  5063. FObjects := TgxSceneRootObject.Create(Self);
  5064. FObjects.Name := 'ObjectRoot';
  5065. FLights := TgxPersistentObjectList.Create;
  5066. FObjectsSorting := osRenderBlendedLast;
  5067. FVisibilityCulling := vcNone;
  5068. // actual maximum number of lights is stored in TgxSceneViewer
  5069. FLights.Count := 8;
  5070. FInitializableObjects := TgxInitializableObjectList.Create;
  5071. end;
  5072. destructor TgxScene.Destroy;
  5073. begin
  5074. InitializableObjects.Free;
  5075. FObjects.DestroyHandles;
  5076. FLights.Free;
  5077. FObjects.Free;
  5078. if Assigned(FBuffers) then
  5079. FreeAndNil(FBuffers);
  5080. inherited Destroy;
  5081. end;
  5082. procedure TgxScene.AddLight(aLight: TgxLightSource);
  5083. var
  5084. i: Integer;
  5085. begin
  5086. for i := 0 to FLights.Count - 1 do
  5087. if FLights.List^[i] = nil then
  5088. begin
  5089. FLights.List^[i] := aLight;
  5090. aLight.FLightID := i;
  5091. Break;
  5092. end;
  5093. end;
  5094. procedure TgxScene.RemoveLight(aLight: TgxLightSource);
  5095. var
  5096. idx: Integer;
  5097. begin
  5098. idx := FLights.IndexOf(aLight);
  5099. if idx >= 0 then
  5100. FLights[idx] := nil;
  5101. end;
  5102. procedure TgxScene.AddLights(anObj: TgxBaseSceneObject);
  5103. var
  5104. i: Integer;
  5105. begin
  5106. if anObj is TgxLightSource then
  5107. AddLight(TgxLightSource(anObj));
  5108. for i := 0 to anObj.Count - 1 do
  5109. AddLights(anObj.Children[i]);
  5110. end;
  5111. procedure TgxScene.RemoveLights(anObj: TgxBaseSceneObject);
  5112. var
  5113. i: Integer;
  5114. begin
  5115. if anObj is TgxLightSource then
  5116. RemoveLight(TgxLightSource(anObj));
  5117. for i := 0 to anObj.Count - 1 do
  5118. RemoveLights(anObj.Children[i]);
  5119. end;
  5120. procedure TgxScene.ShutdownAllLights;
  5121. procedure DoShutdownLight(obj: TgxBaseSceneObject);
  5122. var
  5123. i: Integer;
  5124. begin
  5125. if obj is TgxLightSource then
  5126. TgxLightSource(obj).Shining := False;
  5127. for i := 0 to obj.Count - 1 do
  5128. DoShutdownLight(obj[i]);
  5129. end;
  5130. begin
  5131. DoShutdownLight(FObjects);
  5132. end;
  5133. procedure TgxScene.AddBuffer(aBuffer: TgxSceneBuffer);
  5134. begin
  5135. if not Assigned(FBuffers) then
  5136. FBuffers := TgxPersistentObjectList.Create;
  5137. if FBuffers.IndexOf(aBuffer) < 0 then
  5138. begin
  5139. FBuffers.Add(aBuffer);
  5140. if FBaseContext = nil then
  5141. FBaseContext := TgxSceneBuffer(FBuffers[0]).RenderingContext;
  5142. if (FBuffers.Count > 1) and Assigned(FBaseContext) then
  5143. aBuffer.RenderingContext.ShareLists(FBaseContext);
  5144. end;
  5145. end;
  5146. procedure TgxScene.RemoveBuffer(aBuffer: TgxSceneBuffer);
  5147. var
  5148. i: Integer;
  5149. begin
  5150. if Assigned(FBuffers) then
  5151. begin
  5152. i := FBuffers.IndexOf(aBuffer);
  5153. if i >= 0 then
  5154. begin
  5155. if FBuffers.Count = 1 then
  5156. begin
  5157. FreeAndNil(FBuffers);
  5158. FBaseContext := nil;
  5159. end
  5160. else
  5161. begin
  5162. FBuffers.Delete(i);
  5163. FBaseContext := TgxSceneBuffer(FBuffers[0]).RenderingContext;
  5164. end;
  5165. end;
  5166. end;
  5167. end;
  5168. procedure TgxScene.GetChildren(AProc: TGetChildProc; Root: TComponent);
  5169. begin
  5170. FObjects.GetChildren(AProc, Root);
  5171. end;
  5172. procedure TgxScene.SetChildOrder(AChild: TComponent; Order: Integer);
  5173. begin
  5174. (AChild as TgxBaseSceneObject).Index := Order;
  5175. end;
  5176. function TgxScene.IsUpdating: Boolean;
  5177. begin
  5178. Result := (FUpdateCount <> 0) or (csLoading in ComponentState) or (csDestroying in ComponentState);
  5179. end;
  5180. procedure TgxScene.BeginUpdate;
  5181. begin
  5182. Inc(FUpdateCount);
  5183. end;
  5184. procedure TgxScene.EndUpdate;
  5185. begin
  5186. Assert(FUpdateCount > 0);
  5187. Dec(FUpdateCount);
  5188. if FUpdateCount = 0 then
  5189. NotifyChange(Self);
  5190. end;
  5191. procedure TgxScene.SetObjectsSorting(const val: TgxObjectsSorting);
  5192. begin
  5193. if FObjectsSorting <> val then
  5194. begin
  5195. if val = osInherited then
  5196. FObjectsSorting := osRenderBlendedLast
  5197. else
  5198. FObjectsSorting := val;
  5199. NotifyChange(Self);
  5200. end;
  5201. end;
  5202. procedure TgxScene.SetVisibilityCulling(const val: TgxVisibilityCulling);
  5203. begin
  5204. if FVisibilityCulling <> val then
  5205. begin
  5206. if val = vcInherited then
  5207. FVisibilityCulling := vcNone
  5208. else
  5209. FVisibilityCulling := val;
  5210. NotifyChange(Self);
  5211. end;
  5212. end;
  5213. procedure TgxScene.ReadState(reader: TReader);
  5214. var
  5215. SaveRoot: TComponent;
  5216. begin
  5217. SaveRoot := reader.Root;
  5218. try
  5219. if Owner <> nil then
  5220. reader.Root := Owner;
  5221. inherited;
  5222. finally
  5223. reader.Root := SaveRoot;
  5224. end;
  5225. end;
  5226. procedure TgxScene.Progress(const deltaTime, newTime: Double);
  5227. var
  5228. pt: TgxProgressTimes;
  5229. begin
  5230. pt.deltaTime := deltaTime;
  5231. pt.newTime := newTime;
  5232. FCurrentDeltaTime := deltaTime;
  5233. if Assigned(FOnBeforeProgress) then
  5234. FOnBeforeProgress(Self, deltaTime, newTime);
  5235. FObjects.DoProgress(pt);
  5236. if Assigned(FOnProgress) then
  5237. FOnProgress(Self, deltaTime, newTime);
  5238. end;
  5239. procedure TgxScene.SaveToFile(const fileName: string);
  5240. var
  5241. stream: TStream;
  5242. begin
  5243. stream := TFileStream.Create(fileName, fmCreate);
  5244. try
  5245. SaveToStream(stream);
  5246. finally
  5247. stream.Free;
  5248. end;
  5249. end;
  5250. procedure TgxScene.LoadFromFile(const fileName: string);
  5251. procedure CheckResFileStream(stream: TStream);
  5252. var
  5253. n: Integer;
  5254. B: Byte;
  5255. begin
  5256. n := stream.Position;
  5257. stream.Read(B, SizeOf(B));
  5258. stream.Position := n;
  5259. if B = $FF then
  5260. stream.ReadResHeader;
  5261. end;
  5262. var
  5263. stream: TStream;
  5264. begin
  5265. stream := TFileStream.Create(fileName, fmOpenRead);
  5266. try
  5267. CheckResFileStream(stream);
  5268. LoadFromStream(stream);
  5269. finally
  5270. stream.Free;
  5271. end;
  5272. end;
  5273. procedure TgxScene.SaveToTextFile(const fileName: string);
  5274. var
  5275. mem: TMemoryStream;
  5276. fil: TStream;
  5277. begin
  5278. mem := TMemoryStream.Create;
  5279. fil := TFileStream.Create(fileName, fmCreate);
  5280. try
  5281. SaveToStream(mem);
  5282. mem.Position := 0;
  5283. ObjectBinaryToText(mem, fil);
  5284. finally
  5285. fil.Free;
  5286. mem.Free;
  5287. end;
  5288. end;
  5289. procedure TgxScene.LoadFromTextFile(const fileName: string);
  5290. var
  5291. mem: TMemoryStream;
  5292. fil: TStream;
  5293. begin
  5294. mem := TMemoryStream.Create;
  5295. fil := TFileStream.Create(fileName, fmOpenRead);
  5296. try
  5297. ObjectTextToBinary(fil, mem);
  5298. mem.Position := 0;
  5299. LoadFromStream(mem);
  5300. finally
  5301. fil.Free;
  5302. mem.Free;
  5303. end;
  5304. end;
  5305. procedure TgxScene.LoadFromStream(aStream: TStream);
  5306. var
  5307. fixups: TStringList;
  5308. i: Integer;
  5309. obj: TgxBaseSceneObject;
  5310. begin
  5311. fixups := TStringList.Create;
  5312. try
  5313. if Assigned(FBuffers) then
  5314. begin
  5315. for i := 0 to FBuffers.Count - 1 do
  5316. fixups.AddObject(TgxSceneBuffer(FBuffers[i]).Camera.Name, FBuffers[i]);
  5317. end;
  5318. ShutdownAllLights;
  5319. // will remove Viewer from FBuffers
  5320. Objects.DeleteChildren;
  5321. aStream.ReadComponent(Self);
  5322. for i := 0 to fixups.Count - 1 do
  5323. begin
  5324. obj := FindSceneObject(fixups[i]);
  5325. if obj is TgxCamera then
  5326. TgxSceneBuffer(fixups.Objects[i]).Camera := TgxCamera(obj)
  5327. else { can assign default camera (if existing, of course) instead }
  5328. ;
  5329. end;
  5330. finally
  5331. fixups.Free;
  5332. end;
  5333. end;
  5334. procedure TgxScene.SaveToStream(aStream: TStream);
  5335. begin
  5336. aStream.WriteComponent(Self);
  5337. end;
  5338. function TgxScene.FindSceneObject(const aName: string): TgxBaseSceneObject;
  5339. begin
  5340. Result := FObjects.FindChild(aName, False);
  5341. end;
  5342. function TgxScene.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
  5343. intersectNormal: PVector4f = nil): TgxBaseSceneObject;
  5344. var
  5345. bestDist2: Single;
  5346. bestHit: TgxBaseSceneObject;
  5347. iPoint, iNormal: TVector4f;
  5348. pINormal: PVector4f;
  5349. function RecursiveDive(baseObject: TgxBaseSceneObject): TgxBaseSceneObject;
  5350. var
  5351. i: Integer;
  5352. curObj: TgxBaseSceneObject;
  5353. dist2: Single;
  5354. fNear, fFar: Single;
  5355. begin
  5356. Result := nil;
  5357. for i := 0 to baseObject.Count - 1 do
  5358. begin
  5359. curObj := baseObject.Children[i];
  5360. if curObj.Visible then
  5361. begin
  5362. if RayCastAABBIntersect(rayStart, rayVector, curObj.AxisAlignedBoundingBoxAbsoluteEx, fNear, fFar) then
  5363. begin
  5364. if fNear * fNear > bestDist2 then
  5365. begin
  5366. if not PointInAABB(rayStart, curObj.AxisAlignedBoundingBoxAbsoluteEx) then
  5367. continue;
  5368. end;
  5369. if curObj.RayCastIntersect(rayStart, rayVector, @iPoint, pINormal) then
  5370. begin
  5371. dist2 := VectorDistance2(rayStart, iPoint);
  5372. if dist2 < bestDist2 then
  5373. begin
  5374. bestHit := curObj;
  5375. bestDist2 := dist2;
  5376. if Assigned(intersectPoint) then
  5377. intersectPoint^ := iPoint;
  5378. if Assigned(intersectNormal) then
  5379. intersectNormal^ := iNormal;
  5380. end;
  5381. end;
  5382. RecursiveDive(curObj);
  5383. end;
  5384. end;
  5385. end;
  5386. end;
  5387. begin
  5388. bestDist2 := 1E20;
  5389. bestHit := nil;
  5390. if Assigned(intersectNormal) then
  5391. pINormal := @iNormal
  5392. else
  5393. pINormal := nil;
  5394. RecursiveDive(Objects);
  5395. Result := bestHit;
  5396. end;
  5397. procedure TgxScene.NotifyChange(Sender: TObject);
  5398. var
  5399. i: Integer;
  5400. begin
  5401. if (not IsUpdating) and Assigned(FBuffers) then
  5402. for i := 0 to FBuffers.Count - 1 do
  5403. TgxSceneBuffer(FBuffers[i]).NotifyChange(Self);
  5404. end;
  5405. procedure TgxScene.SetupLights(maxLights: Integer);
  5406. var
  5407. i: Integer;
  5408. lightSource: TgxLightSource;
  5409. nbLights: Integer;
  5410. lPos: TVector4f;
  5411. begin
  5412. nbLights := FLights.Count;
  5413. if nbLights > maxLights then
  5414. nbLights := maxLights;
  5415. // setup all light sources
  5416. with CurrentContext.gxStates, CurrentContext.PipeLineTransformation do
  5417. begin
  5418. for i := 0 to nbLights - 1 do
  5419. begin
  5420. lightSource := TgxLightSource(FLights[i]);
  5421. if Assigned(lightSource) then
  5422. with lightSource do
  5423. begin
  5424. LightEnabling[FLightID] := Shining;
  5425. if Shining then
  5426. begin
  5427. if FixedFunctionPipeLight then
  5428. begin
  5429. RebuildMatrix;
  5430. if LightStyle in [lsParallel, lsParallelSpot] then
  5431. begin
  5432. SetModelMatrix(AbsoluteMatrix);
  5433. glLightfv(GL_LIGHT0 + FLightID, GL_POSITION, @SpotDirection.AsAddress^);
  5434. end
  5435. else
  5436. begin
  5437. SetModelMatrix(Parent.AbsoluteMatrix);
  5438. glLightfv(GL_LIGHT0 + FLightID, GL_POSITION, @Position.AsAddress^);
  5439. end;
  5440. if LightStyle in [lsSpot, lsParallelSpot] then
  5441. begin
  5442. if FSpotCutOff <> 180 then
  5443. glLightfv(GL_LIGHT0 + FLightID, GL_SPOT_DIRECTION, @FSpotDirection.AsAddress^);
  5444. end;
  5445. end;
  5446. lPos := lightSource.AbsolutePosition;
  5447. if LightStyle in [lsParallel, lsParallelSpot] then
  5448. lPos.W := 0.0
  5449. else
  5450. lPos.W := 1.0;
  5451. LightPosition[FLightID] := lPos;
  5452. LightSpotDirection[FLightID] := lightSource.SpotDirection.AsAffineVector;
  5453. LightAmbient[FLightID] := FAmbient.Color;
  5454. LightDiffuse[FLightID] := FDiffuse.Color;
  5455. LightSpecular[FLightID] := FSpecular.Color;
  5456. LightConstantAtten[FLightID] := FConstAttenuation;
  5457. LightLinearAtten[FLightID] := FLinearAttenuation;
  5458. LightQuadraticAtten[FLightID] := FQuadraticAttenuation;
  5459. LightSpotExponent[FLightID] := FSpotExponent;
  5460. LightSpotCutoff[FLightID] := FSpotCutOff;
  5461. end;
  5462. end
  5463. else
  5464. LightEnabling[i] := False;
  5465. end;
  5466. // turn off other lights
  5467. for i := nbLights to maxLights - 1 do
  5468. LightEnabling[i] := False;
  5469. SetModelMatrix(IdentityHmgMatrix);
  5470. end;
  5471. end;
  5472. // ------------------
  5473. // ------------------ TgxFogEnvironment ------------------
  5474. // ------------------
  5475. // Note: The fog implementation is not conformal with the rest of the scene management
  5476. // because it is viewer bound not scene bound.
  5477. constructor TgxFogEnvironment.Create(AOwner: TPersistent);
  5478. begin
  5479. inherited;
  5480. FSceneBuffer := (AOwner as TgxSceneBuffer);
  5481. FFogColor := TgxColor.CreateInitialized(Self, clrBlack);
  5482. FFogMode := fmLinear;
  5483. FFogStart := 10;
  5484. FFogEnd := 1000;
  5485. FFogDistance := fdDefault;
  5486. end;
  5487. destructor TgxFogEnvironment.Destroy;
  5488. begin
  5489. FFogColor.Free;
  5490. inherited Destroy;
  5491. end;
  5492. procedure TgxFogEnvironment.SetFogColor(Value: TgxColor);
  5493. begin
  5494. if Assigned(Value) then
  5495. begin
  5496. FFogColor.Assign(Value);
  5497. NotifyChange(Self);
  5498. end;
  5499. end;
  5500. procedure TgxFogEnvironment.SetFogStart(Value: Single);
  5501. begin
  5502. if Value <> FFogStart then
  5503. begin
  5504. FFogStart := Value;
  5505. NotifyChange(Self);
  5506. end;
  5507. end;
  5508. procedure TgxFogEnvironment.SetFogEnd(Value: Single);
  5509. begin
  5510. if Value <> FFogEnd then
  5511. begin
  5512. FFogEnd := Value;
  5513. NotifyChange(Self);
  5514. end;
  5515. end;
  5516. procedure TgxFogEnvironment.Assign(Source: TPersistent);
  5517. begin
  5518. if Source is TgxFogEnvironment then
  5519. begin
  5520. FFogColor.Assign(TgxFogEnvironment(Source).FFogColor);
  5521. FFogStart := TgxFogEnvironment(Source).FFogStart;
  5522. FFogEnd := TgxFogEnvironment(Source).FFogEnd;
  5523. FFogMode := TgxFogEnvironment(Source).FFogMode;
  5524. FFogDistance := TgxFogEnvironment(Source).FFogDistance;
  5525. NotifyChange(Self);
  5526. end;
  5527. inherited;
  5528. end;
  5529. function TgxFogEnvironment.IsAtDefaultValues: Boolean;
  5530. begin
  5531. Result := VectorEquals(FogColor.Color, FogColor.DefaultColor) and (FogStart = 10) and (FogEnd = 1000) and (FogMode = fmLinear)
  5532. and (FogDistance = fdDefault);
  5533. end;
  5534. procedure TgxFogEnvironment.SetFogMode(Value: TgxFogMode);
  5535. begin
  5536. if Value <> FFogMode then
  5537. begin
  5538. FFogMode := Value;
  5539. NotifyChange(Self);
  5540. end;
  5541. end;
  5542. procedure TgxFogEnvironment.SetFogDistance(const val: TgxFogDistance);
  5543. begin
  5544. if val <> FFogDistance then
  5545. begin
  5546. FFogDistance := val;
  5547. NotifyChange(Self);
  5548. end;
  5549. end;
  5550. var
  5551. vImplemDependantFogDistanceDefault: Integer = -1;
  5552. procedure TgxFogEnvironment.ApplyFog;
  5553. var
  5554. tempActivation: Boolean;
  5555. begin
  5556. with FSceneBuffer do
  5557. begin
  5558. if not Assigned(FRenderingContext) then
  5559. Exit;
  5560. tempActivation := not FRenderingContext.Active;
  5561. if tempActivation then
  5562. FRenderingContext.Activate;
  5563. end;
  5564. case FFogMode of
  5565. fmLinear:
  5566. glFogi(GL_FOG_MODE, GL_LINEAR);
  5567. fmExp:
  5568. begin
  5569. glFogi(GL_FOG_MODE, GL_EXP);
  5570. glFogf(GL_FOG_DENSITY, FFogColor.alpha);
  5571. end;
  5572. fmExp2:
  5573. begin
  5574. glFogi(GL_FOG_MODE, GL_EXP2);
  5575. glFogf(GL_FOG_DENSITY, FFogColor.alpha);
  5576. end;
  5577. end;
  5578. glFogfv(GL_FOG_COLOR, @FFogColor.AsAddress^);
  5579. glFogf(GL_FOG_START, FFogStart);
  5580. glFogf(GL_FOG_END, FFogEnd);
  5581. case FogDistance of
  5582. fdDefault:
  5583. begin
  5584. if vImplemDependantFogDistanceDefault = -1 then
  5585. glGetIntegerv(Cardinal(GL_FOG_DISTANCE_MODE_NV), // GL_FOG_DISTANCE_MODE_NV,
  5586. @vImplemDependantFogDistanceDefault)
  5587. else
  5588. glFogi(Cardinal(GL_FOG_DISTANCE_MODE_NV), vImplemDependantFogDistanceDefault);
  5589. end;
  5590. fdEyePlane:
  5591. glFogi(Cardinal(GL_FOG_DISTANCE_MODE_NV), GL_EYE_PLANE_ABSOLUTE_NV);
  5592. fdEyeRadial:
  5593. glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV);
  5594. else
  5595. Assert(False);
  5596. end;
  5597. if tempActivation then
  5598. FSceneBuffer.RenderingContext.Deactivate;
  5599. end;
  5600. // ------------------
  5601. // ------------------ TgxSceneBuffer ------------------
  5602. // ------------------
  5603. constructor TgxSceneBuffer.Create(AOwner: TPersistent);
  5604. begin
  5605. inherited Create(AOwner);
  5606. // initialize private state variables
  5607. FFogEnvironment := TgxFogEnvironment.Create(Self);
  5608. FBackgroundColor := TColors.SysBtnFace;
  5609. FBackgroundAlpha := 1;
  5610. FAmbientColor := TgxColor.CreateInitialized(Self, clrGray20);
  5611. FDepthTest := True;
  5612. FFaceCulling := True;
  5613. FLighting := True;
  5614. FAntiAliasing := aaDefault;
  5615. FDepthPrecision := dpDefault;
  5616. FColorDepth := cdDefault;
  5617. FShadeModel := smDefault;
  5618. FFogEnable := False;
  5619. FLayer := clMainPlane;
  5620. FAfterRenderEffects := TgxPersistentObjectList.Create;
  5621. FContextOptions := [roDoubleBuffer, roRenderToWindow, roDebugContext];
  5622. ResetPerformanceMonitor;
  5623. end;
  5624. destructor TgxSceneBuffer.Destroy;
  5625. begin
  5626. Melt;
  5627. DestroyRC;
  5628. FAmbientColor.Free;
  5629. FAfterRenderEffects.Free;
  5630. FFogEnvironment.Free;
  5631. inherited Destroy;
  5632. end;
  5633. procedure TgxSceneBuffer.PrepareGLContext;
  5634. begin
  5635. if Assigned(FOnPrepareGLContext) then
  5636. FOnPrepareGLContext(Self);
  5637. end;
  5638. procedure TgxSceneBuffer.SetupRCOptions(Context: TgxContext);
  5639. const
  5640. cColorDepthToColorBits: array [cdDefault .. cdFloat128bits] of Integer = (24, 8, 16, 24, 64, 128); // float_type
  5641. cDepthPrecisionToDepthBits: array [dpDefault .. dp32bits] of Integer = (24, 16, 24, 32);
  5642. var
  5643. locOptions: TgxRCOptions;
  5644. locStencilBits, locAlphaBits, locColorBits: Integer;
  5645. begin
  5646. locOptions := [];
  5647. if roDoubleBuffer in ContextOptions then
  5648. locOptions := locOptions + [rcoDoubleBuffered];
  5649. if roStereo in ContextOptions then
  5650. locOptions := locOptions + [rcoStereo];
  5651. if roDebugContext in ContextOptions then
  5652. locOptions := locOptions + [rcoDebug];
  5653. if roOpenGL_ES2_Context in ContextOptions then
  5654. locOptions := locOptions + [rcoOGL_ES];
  5655. if roNoColorBuffer in ContextOptions then
  5656. locColorBits := 0
  5657. else
  5658. locColorBits := cColorDepthToColorBits[ColorDepth];
  5659. if roStencilBuffer in ContextOptions then
  5660. locStencilBits := 8
  5661. else
  5662. locStencilBits := 0;
  5663. if roDestinationAlpha in ContextOptions then
  5664. locAlphaBits := 8
  5665. else
  5666. locAlphaBits := 0;
  5667. with Context do
  5668. begin
  5669. if roSoftwareMode in ContextOptions then
  5670. Acceleration := chaSoftware
  5671. else
  5672. Acceleration := chaHardware;
  5673. Options := locOptions;
  5674. ColorBits := locColorBits;
  5675. DepthBits := cDepthPrecisionToDepthBits[DepthPrecision];
  5676. StencilBits := locStencilBits;
  5677. AlphaBits := locAlphaBits;
  5678. AccumBits := AccumBufferBits;
  5679. AuxBuffers := 0;
  5680. AntiAliasing := Self.AntiAliasing;
  5681. Layer := Self.Layer;
  5682. { gxStates.ForwardContext := roForwardContext in ContextOptions; }
  5683. PrepareGLContext;
  5684. end;
  5685. end;
  5686. procedure TgxSceneBuffer.CreateRC(AWindowHandle: THandle; memoryContext: Boolean; BufferCount: Integer);
  5687. begin
  5688. DestroyRC;
  5689. FRendering := True;
  5690. try
  5691. // will be freed in DestroyWindowHandle
  5692. FRenderingContext := GXContextManager.CreateContext;
  5693. if not Assigned(FRenderingContext) then
  5694. raise Exception.Create('Failed to create RenderingContext.');
  5695. SetupRCOptions(FRenderingContext);
  5696. if Assigned(FCamera) and Assigned(FCamera.FScene) then
  5697. FCamera.FScene.AddBuffer(Self);
  5698. with FRenderingContext do
  5699. begin
  5700. try
  5701. if memoryContext then
  5702. CreateMemoryContext(AWindowHandle, FViewPort.width, FViewPort.height, BufferCount)
  5703. else
  5704. CreateContext(AWindowHandle);
  5705. except
  5706. FreeAndNil(FRenderingContext);
  5707. raise;
  5708. end;
  5709. end;
  5710. FRenderingContext.Activate;
  5711. try
  5712. // this one should NOT be replaced with an assert
  5713. if (GL_VERSION < 1.1) then
  5714. begin
  5715. ShowMessage(strWrongVersion);
  5716. Abort;
  5717. end;
  5718. // define viewport, this is necessary because the first WM_SIZE message
  5719. // is posted before the rendering context has been created
  5720. FRenderingContext.gxStates.viewport := Vector4iMake(FViewPort.Left, FViewPort.Top, FViewPort.width, FViewPort.height);
  5721. // set up initial context states
  5722. SetupRenderingContext(FRenderingContext);
  5723. FRenderingContext.gxStates.ColorClearValue := ConvertWinColor(FBackgroundColor);
  5724. finally
  5725. FRenderingContext.Deactivate;
  5726. end;
  5727. finally
  5728. FRendering := False;
  5729. end;
  5730. end;
  5731. procedure TgxSceneBuffer.DestroyRC;
  5732. begin
  5733. if Assigned(FRenderingContext) then
  5734. begin
  5735. Melt;
  5736. // for some obscure reason, Mesa3D doesn't like this call... any help welcome
  5737. FreeAndNil(FSelector);
  5738. FreeAndNil(FRenderingContext);
  5739. if Assigned(FCamera) and Assigned(FCamera.FScene) then
  5740. FCamera.FScene.RemoveBuffer(Self);
  5741. end;
  5742. end;
  5743. function TgxSceneBuffer.RCInstantiated: Boolean;
  5744. begin
  5745. Result := Assigned(FRenderingContext);
  5746. end;
  5747. procedure TgxSceneBuffer.Resize(newLeft, newTop, newWidth, newHeight: Integer);
  5748. begin
  5749. if newWidth < 1 then
  5750. newWidth := 1;
  5751. if newHeight < 1 then
  5752. newHeight := 1;
  5753. FViewPort.Left := newLeft;
  5754. FViewPort.Top := newTop;
  5755. FViewPort.width := newWidth;
  5756. FViewPort.height := newHeight;
  5757. if Assigned(FRenderingContext) then
  5758. begin
  5759. FRenderingContext.Activate;
  5760. try
  5761. // Part of workaround for MS OpenGL "black borders" bug
  5762. FRenderingContext.gxStates.viewport := Vector4iMake(FViewPort.Left, FViewPort.Top, FViewPort.width, FViewPort.height);
  5763. finally
  5764. FRenderingContext.Deactivate;
  5765. end;
  5766. end;
  5767. end;
  5768. function TgxSceneBuffer.Acceleration: TgxContextAcceleration;
  5769. begin
  5770. if Assigned(FRenderingContext) then
  5771. Result := FRenderingContext.Acceleration
  5772. else
  5773. Result := chaUnknown;
  5774. end;
  5775. procedure TgxSceneBuffer.SetupRenderingContext(Context: TgxContext);
  5776. procedure SetState(bool: Boolean; csState: TgxState);
  5777. begin
  5778. case bool of
  5779. True:
  5780. Context.gxStates.PerformEnable(csState);
  5781. False:
  5782. Context.gxStates.PerformDisable(csState);
  5783. end;
  5784. end;
  5785. var
  5786. LColorDepth: Cardinal;
  5787. begin
  5788. if not Assigned(Context) then
  5789. Exit;
  5790. if not(roForwardContext in ContextOptions) then
  5791. begin
  5792. glLightModelfv(GL_LIGHT_MODEL_AMBIENT, @FAmbientColor.AsAddress^);
  5793. if roTwoSideLighting in FContextOptions then
  5794. glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)
  5795. else
  5796. glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
  5797. glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
  5798. case ShadeModel of
  5799. smDefault, smSmooth:
  5800. glShadeModel(GL_SMOOTH);
  5801. smFlat:
  5802. glShadeModel(GL_FLAT);
  5803. else
  5804. Assert(False, strErrorEx + strUnknownType);
  5805. end;
  5806. end;
  5807. with Context.gxStates do
  5808. begin
  5809. Enable(stNormalize);
  5810. SetState(DepthTest, stDepthTest);
  5811. SetState(FaceCulling, stCullFace);
  5812. SetState(Lighting, stLighting);
  5813. SetState(FogEnable, stFog);
  5814. Disable(stDepthClamp);
  5815. if not(roForwardContext in ContextOptions) then
  5816. begin
  5817. glGetIntegerv(GL_BLUE_BITS, @LColorDepth); // could've used red or green too
  5818. SetState((LColorDepth < 8), stDither);
  5819. end;
  5820. ResetAllTextureMatrix;
  5821. end;
  5822. end;
  5823. function TgxSceneBuffer.GetLimit(Which: TgxLimitType): Integer;
  5824. var
  5825. VP: array [0 .. 1] of Double;
  5826. begin
  5827. case Which of
  5828. limClipPlanes:
  5829. glGetIntegerv(GL_MAX_CLIP_PLANES, @Result);
  5830. limEvalOrder:
  5831. glGetIntegerv(GL_MAX_EVAL_ORDER, @Result);
  5832. limLights:
  5833. glGetIntegerv(GL_MAX_LIGHTS, @Result);
  5834. limListNesting:
  5835. glGetIntegerv(GL_MAX_LIST_NESTING, @Result);
  5836. limModelViewStack:
  5837. glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, @Result);
  5838. limNameStack:
  5839. glGetIntegerv(GL_MAX_NAME_STACK_DEPTH, @Result);
  5840. limPixelMapTable:
  5841. glGetIntegerv(GL_MAX_PIXEL_MAP_TABLE, @Result);
  5842. limProjectionStack:
  5843. glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, @Result);
  5844. limTextureSize:
  5845. glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Result);
  5846. limTextureStack:
  5847. glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH, @Result);
  5848. limViewportDims:
  5849. begin
  5850. glGetDoublev(GL_MAX_VIEWPORT_DIMS, @VP);
  5851. if VP[0] > VP[1] then
  5852. Result := Round(VP[0])
  5853. else
  5854. Result := Round(VP[1]);
  5855. end;
  5856. limAccumAlphaBits: glGetIntegerv(GL_ACCUM_ALPHA_BITS, @Result);
  5857. limAccumBlueBits: glGetIntegerv(GL_ACCUM_BLUE_BITS, @Result);
  5858. limAccumGreenBits: glGetIntegerv(GL_ACCUM_GREEN_BITS, @Result);
  5859. limAccumRedBits: glGetIntegerv(GL_ACCUM_RED_BITS, @Result);
  5860. limAlphaBits: glGetIntegerv(GL_ALPHA_BITS, @Result);
  5861. limAuxBuffers: glGetIntegerv(GL_AUX_BUFFERS, @Result);
  5862. limDepthBits: glGetIntegerv(GL_DEPTH_BITS, @Result);
  5863. limStencilBits: glGetIntegerv(GL_STENCIL_BITS, @Result);
  5864. limBlueBits: glGetIntegerv(GL_BLUE_BITS, @Result);
  5865. limGreenBits: glGetIntegerv(GL_GREEN_BITS, @Result);
  5866. limRedBits: glGetIntegerv(GL_RED_BITS, @Result);
  5867. limIndexBits: glGetIntegerv(GL_INDEX_BITS, @Result);
  5868. limStereo: glGetIntegerv(GL_STEREO, @Result);
  5869. limDoubleBuffer: glGetIntegerv(GL_DOUBLEBUFFER, @Result);
  5870. limSubpixelBits: glGetIntegerv(GL_SUBPIXEL_BITS, @Result);
  5871. limNbTextureUnits: glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, @Result);
  5872. else
  5873. Result := 0;
  5874. end;
  5875. end;
  5876. procedure TgxSceneBuffer.RenderToFile(const AFile: string; DPI: Integer);
  5877. var
  5878. ABitmap: TBitmap;
  5879. saveAllowed: Boolean;
  5880. fileName: string;
  5881. begin
  5882. Assert((not FRendering), strAlreadyRendering);
  5883. ABitmap := TBitmap.Create;
  5884. try
  5885. ABitmap.width := FViewPort.width;
  5886. ABitmap.height := FViewPort.height;
  5887. { TODO -oPW : E2129 Cannot assign to a read-only property }
  5888. // aBitmap.PixelFormat := glpf24Bit;
  5889. RenderToBitmap(ABitmap, DPI);
  5890. fileName := AFile;
  5891. if fileName = '' then
  5892. saveAllowed := SavePictureDialog(fileName)
  5893. else
  5894. saveAllowed := True;
  5895. if saveAllowed then
  5896. begin
  5897. if FileExists(fileName) then
  5898. saveAllowed := QuestionDlg(Format('Overwrite file %s?', [fileName]));
  5899. if saveAllowed then
  5900. ABitmap.SaveToFile(fileName);
  5901. end;
  5902. finally
  5903. ABitmap.Free;
  5904. end;
  5905. end;
  5906. procedure TgxSceneBuffer.RenderToFile(const AFile: string; bmpWidth, bmpHeight: Integer);
  5907. var
  5908. ABitmap: TBitmap;
  5909. saveAllowed: Boolean;
  5910. fileName: string;
  5911. begin
  5912. Assert((not FRendering), strAlreadyRendering);
  5913. ABitmap := TBitmap.Create;
  5914. try
  5915. ABitmap.width := bmpWidth;
  5916. ABitmap.height := bmpHeight;
  5917. { TODO -oPW : E2129 Cannot assign to a read-only property }
  5918. (* GLS-> aBitmap.PixelFormat := glpf24Bit; *)
  5919. RenderToBitmap(ABitmap,
  5920. // GLS-> (GetDeviceLogicalPixelsX(Cardinal(ABitmap.Canvas.Handle)) * bmpWidth) div
  5921. (GetDeviceLogicalPixelsX(ABitmap.Handle) * bmpWidth) div FViewPort.width);
  5922. fileName := AFile;
  5923. if fileName = '' then
  5924. saveAllowed := SavePictureDialog(fileName)
  5925. else
  5926. saveAllowed := True;
  5927. if saveAllowed then
  5928. begin
  5929. if FileExists(fileName) then
  5930. saveAllowed := QuestionDlg(Format('Overwrite file %s?', [fileName]));
  5931. if saveAllowed then
  5932. ABitmap.SaveToFile(fileName);
  5933. end;
  5934. finally
  5935. ABitmap.Free;
  5936. end;
  5937. end;
  5938. function TgxSceneBuffer.CreateSnapShot: TgxBitmap32;
  5939. begin
  5940. Result := TgxBitmap32.Create;
  5941. Result.width := FViewPort.width;
  5942. Result.height := FViewPort.height;
  5943. if Assigned(Camera) and Assigned(Camera.Scene) then
  5944. begin
  5945. FRenderingContext.Activate;
  5946. try
  5947. Result.ReadPixels(rect(0, 0, FViewPort.width, FViewPort.height));
  5948. finally
  5949. FRenderingContext.Deactivate;
  5950. end;
  5951. end;
  5952. end;
  5953. function TgxSceneBuffer.CreateSnapShotBitmap: TBitmap;
  5954. var
  5955. bmp32: TgxBitmap32;
  5956. begin
  5957. bmp32 := CreateSnapShot;
  5958. try
  5959. Result := bmp32.Create32BitsBitmap;
  5960. finally
  5961. bmp32.Free;
  5962. end;
  5963. end;
  5964. procedure TgxSceneBuffer.CopyToTexture(aTexture: TgxTexture);
  5965. begin
  5966. CopyToTexture(aTexture, 0, 0, width, height, 0, 0);
  5967. end;
  5968. procedure TgxSceneBuffer.CopyToTexture(aTexture: TgxTexture; xSrc, ySrc, AWidth, AHeight: Integer; xDest, yDest: Integer;
  5969. glCubeFace: GLEnum = 0);
  5970. var
  5971. bindTarget: TglTextureTarget;
  5972. begin
  5973. if RenderingContext <> nil then
  5974. begin
  5975. RenderingContext.Activate;
  5976. try
  5977. if not(aTexture.Image is TgxBlankImage) then
  5978. aTexture.ImageClassName := TgxBlankImage.ClassName;
  5979. if aTexture.Image.width <> AWidth then
  5980. TgxBlankImage(aTexture.Image).width := AWidth;
  5981. if aTexture.Image.height <> AHeight then
  5982. TgxBlankImage(aTexture.Image).height := AHeight;
  5983. if aTexture.Image.Depth <> 0 then
  5984. TgxBlankImage(aTexture.Image).Depth := 0;
  5985. if TgxBlankImage(aTexture.Image).CubeMap <> (glCubeFace > 0) then
  5986. TgxBlankImage(aTexture.Image).CubeMap := (glCubeFace > 0);
  5987. bindTarget := aTexture.Image.NativeTextureTarget;
  5988. RenderingContext.gxStates.TextureBinding[0, bindTarget] := aTexture.Handle;
  5989. if glCubeFace > 0 then
  5990. glCopyTexSubImage2D(glCubeFace, 0, xDest, yDest, xSrc, ySrc, AWidth, AHeight)
  5991. else
  5992. glCopyTexSubImage2D(DecodeTextureTarget(bindTarget), 0, xDest, yDest, xSrc, ySrc, AWidth, AHeight)
  5993. finally
  5994. RenderingContext.Deactivate;
  5995. end;
  5996. end;
  5997. end;
  5998. procedure TgxSceneBuffer.SaveAsFloatToFile(const aFilename: string);
  5999. var
  6000. Data: Pointer;
  6001. DataSize: Integer;
  6002. stream: TMemoryStream;
  6003. const
  6004. FloatSize = 4;
  6005. begin
  6006. if Assigned(Camera) and Assigned(Camera.Scene) then
  6007. begin
  6008. DataSize := width * height * FloatSize * FloatSize;
  6009. GetMem(Data, DataSize);
  6010. FRenderingContext.Activate;
  6011. try
  6012. glReadPixels(0, 0, width, height, GL_RGBA, GL_FLOAT, Data);
  6013. glGetError;
  6014. stream := TMemoryStream.Create;
  6015. try
  6016. stream.Write(Data^, DataSize);
  6017. stream.SaveToFile(aFilename);
  6018. finally
  6019. stream.Free;
  6020. end;
  6021. finally
  6022. FRenderingContext.Deactivate;
  6023. FreeMem(Data);
  6024. end;
  6025. end;
  6026. end;
  6027. procedure TgxSceneBuffer.SetViewPort(x, y, W, H: Integer);
  6028. begin
  6029. with FViewPort do
  6030. begin
  6031. Left := x;
  6032. Top := y;
  6033. width := W;
  6034. height := H;
  6035. end;
  6036. NotifyChange(Self);
  6037. end;
  6038. function TgxSceneBuffer.width: Integer;
  6039. begin
  6040. Result := FViewPort.width;
  6041. end;
  6042. function TgxSceneBuffer.height: Integer;
  6043. begin
  6044. Result := FViewPort.height;
  6045. end;
  6046. procedure TgxSceneBuffer.Freeze;
  6047. begin
  6048. if Freezed then
  6049. Exit;
  6050. if RenderingContext = nil then
  6051. Exit;
  6052. Render;
  6053. FFreezed := True;
  6054. RenderingContext.Activate;
  6055. try
  6056. FFreezeBuffer := AllocMem(FViewPort.width * FViewPort.height * 4);
  6057. glReadPixels(0, 0, FViewPort.width, FViewPort.height, GL_RGBA, GL_UNSIGNED_BYTE, FFreezeBuffer);
  6058. FFreezedViewPort := FViewPort;
  6059. finally
  6060. RenderingContext.Deactivate;
  6061. end;
  6062. end;
  6063. procedure TgxSceneBuffer.Melt;
  6064. begin
  6065. if not Freezed then
  6066. Exit;
  6067. FreeMem(FFreezeBuffer);
  6068. FFreezeBuffer := nil;
  6069. FFreezed := False;
  6070. end;
  6071. procedure TgxSceneBuffer.RenderToBitmap(ABitmap: TBitmap; DPI: Integer);
  6072. var
  6073. nativeContext: TgxContext;
  6074. aColorBits: Integer;
  6075. begin
  6076. Assert((not FRendering), strAlreadyRendering);
  6077. FRendering := True;
  6078. nativeContext := RenderingContext;
  6079. try
  6080. aColorBits := PixelFormatToColorBits(ABitmap.PixelFormat);
  6081. if aColorBits < 8 then
  6082. aColorBits := 8;
  6083. FRenderingContext := GXContextManager.CreateContext;
  6084. SetupRCOptions(FRenderingContext);
  6085. with FRenderingContext do
  6086. begin
  6087. Options := []; // no such things for bitmap rendering
  6088. ColorBits := aColorBits; // honour Bitmap's pixel depth
  6089. AntiAliasing := aaNone; // no AA for bitmap rendering
  6090. CreateContext(ABitmap.Handle); // CreateContext(ABitmap.Canvas.Handle);
  6091. end;
  6092. try
  6093. FRenderingContext.Activate;
  6094. try
  6095. SetupRenderingContext(FRenderingContext);
  6096. FRenderingContext.gxStates.ColorClearValue := ConvertWinColor(FBackgroundColor);
  6097. // set the desired viewport and limit output to this rectangle
  6098. with FViewPort do
  6099. begin
  6100. Left := 0;
  6101. Top := 0;
  6102. width := ABitmap.width;
  6103. height := ABitmap.height;
  6104. FRenderingContext.gxStates.viewport := Vector4iMake(Left, Top, width, height);
  6105. end;
  6106. ClearBuffers;
  6107. FRenderDPI := DPI;
  6108. if FRenderDPI = 0 then
  6109. FRenderDPI := GetDeviceLogicalPixelsX(ABitmap.Handle);
  6110. // render
  6111. DoBaseRender(FViewPort, FRenderDPI, dsPrinting, nil);
  6112. if nativeContext <> nil then
  6113. FViewPort := TRectangle(nativeContext.gxStates.viewport);
  6114. glFinish;
  6115. finally
  6116. FRenderingContext.Deactivate;
  6117. end;
  6118. finally
  6119. FRenderingContext.Free;
  6120. end;
  6121. finally
  6122. FRenderingContext := nativeContext;
  6123. FRendering := False;
  6124. end;
  6125. if Assigned(FAfterRender) then
  6126. if Owner is TComponent then
  6127. if not(csDesigning in TComponent(Owner).ComponentState) then
  6128. FAfterRender(Self);
  6129. end;
  6130. procedure TgxSceneBuffer.ShowInfo(Modal: Boolean);
  6131. begin
  6132. if not Assigned(FRenderingContext) then
  6133. Exit;
  6134. // most info is available with active context only
  6135. FRenderingContext.Activate;
  6136. try
  6137. InvokeInfoForm(Self, Modal);
  6138. finally
  6139. FRenderingContext.Deactivate;
  6140. end;
  6141. end;
  6142. procedure TgxSceneBuffer.ResetPerformanceMonitor;
  6143. begin
  6144. FFramesPerSecond := 0;
  6145. FFrameCount := 0;
  6146. FFirstPerfCounter := 0;
  6147. end;
  6148. procedure TgxSceneBuffer.PushViewMatrix(const newMatrix: TMatrix4f);
  6149. var
  6150. n: Integer;
  6151. begin
  6152. n := Length(FViewMatrixStack);
  6153. SetLength(FViewMatrixStack, n + 1);
  6154. FViewMatrixStack[n] := RenderingContext.PipeLineTransformation.ViewMatrix^;
  6155. RenderingContext.PipeLineTransformation.SetViewMatrix(newMatrix);
  6156. end;
  6157. procedure TgxSceneBuffer.PopViewMatrix;
  6158. var
  6159. n: Integer;
  6160. begin
  6161. n := High(FViewMatrixStack);
  6162. Assert(n >= 0, 'Unbalanced PopViewMatrix');
  6163. RenderingContext.PipeLineTransformation.SetViewMatrix(FViewMatrixStack[n]);
  6164. SetLength(FViewMatrixStack, n);
  6165. end;
  6166. procedure TgxSceneBuffer.PushProjectionMatrix(const newMatrix: TMatrix4f);
  6167. var
  6168. n: Integer;
  6169. begin
  6170. n := Length(FProjectionMatrixStack);
  6171. SetLength(FProjectionMatrixStack, n + 1);
  6172. FProjectionMatrixStack[n] := RenderingContext.PipeLineTransformation.ProjectionMatrix^;
  6173. RenderingContext.PipeLineTransformation.SetProjectionMatrix(newMatrix);
  6174. end;
  6175. procedure TgxSceneBuffer.PopProjectionMatrix;
  6176. var
  6177. n: Integer;
  6178. begin
  6179. n := High(FProjectionMatrixStack);
  6180. Assert(n >= 0, 'Unbalanced PopProjectionMatrix');
  6181. RenderingContext.PipeLineTransformation.SetProjectionMatrix(FProjectionMatrixStack[n]);
  6182. SetLength(FProjectionMatrixStack, n);
  6183. end;
  6184. function TgxSceneBuffer.ProjectionMatrix;
  6185. begin
  6186. Result := RenderingContext.PipeLineTransformation.ProjectionMatrix^;
  6187. end;
  6188. function TgxSceneBuffer.ViewMatrix: TMatrix4f;
  6189. begin
  6190. Result := RenderingContext.PipeLineTransformation.ViewMatrix^;
  6191. end;
  6192. function TgxSceneBuffer.ModelMatrix: TMatrix4f;
  6193. begin
  6194. Result := RenderingContext.PipeLineTransformation.ModelMatrix^;
  6195. end;
  6196. function TgxSceneBuffer.OrthoScreenToWorld(screenX, screenY: Integer): TAffineVector;
  6197. var
  6198. camPos, camUp, camRight: TAffineVector;
  6199. f: Single;
  6200. begin
  6201. if Assigned(FCamera) then
  6202. begin
  6203. SetVector(camPos, FCameraAbsolutePosition);
  6204. if Camera.TargetObject <> nil then
  6205. begin
  6206. SetVector(camUp, FCamera.AbsoluteUpVectorToTarget);
  6207. SetVector(camRight, FCamera.AbsoluteRightVectorToTarget);
  6208. end
  6209. else
  6210. begin
  6211. SetVector(camUp, Camera.AbsoluteUp);
  6212. SetVector(camRight, Camera.AbsoluteRight);
  6213. end;
  6214. f := 100 * FCamera.NearPlaneBias / (FCamera.FocalLength * FCamera.SceneScale);
  6215. if FViewPort.width > FViewPort.height then
  6216. f := f / FViewPort.width
  6217. else
  6218. f := f / FViewPort.height;
  6219. SetVector(Result, VectorCombine3(camPos, camUp, camRight, 1, (screenY - (FViewPort.height div 2)) * f,
  6220. (screenX - (FViewPort.width div 2)) * f));
  6221. end
  6222. else
  6223. Result := NullVector;
  6224. end;
  6225. function TgxSceneBuffer.ScreenToWorld(const aPoint: TAffineVector): TAffineVector;
  6226. var
  6227. rslt: TVector4f;
  6228. begin
  6229. if Assigned(FCamera) and UnProject(VectorMake(aPoint), RenderingContext.PipeLineTransformation.ViewProjectionMatrix^,
  6230. PHomogeneousIntVector(@FViewPort)^, rslt) then
  6231. Result := Vector3fMake(rslt)
  6232. else
  6233. Result := aPoint;
  6234. end;
  6235. function TgxSceneBuffer.ScreenToWorld(const aPoint: TVector4f): TVector4f;
  6236. begin
  6237. MakePoint(Result, ScreenToWorld(AffineVectorMake(aPoint)));
  6238. end;
  6239. function TgxSceneBuffer.ScreenToWorld(screenX, screenY: Integer): TAffineVector;
  6240. begin
  6241. Result := ScreenToWorld(AffineVectorMake(screenX, FViewPort.height - screenY, 0));
  6242. end;
  6243. function TgxSceneBuffer.WorldToScreen(const aPoint: TAffineVector): TAffineVector;
  6244. var
  6245. rslt: TVector4f;
  6246. begin
  6247. RenderingContext.Activate;
  6248. try
  6249. PrepareRenderingMatrices(FViewPort, FRenderDPI);
  6250. if Assigned(FCamera) and Project(VectorMake(aPoint), RenderingContext.PipeLineTransformation.ViewProjectionMatrix^,
  6251. TVector4i(FViewPort), rslt) then
  6252. Result := Vector3fMake(rslt)
  6253. else
  6254. Result := aPoint;
  6255. finally
  6256. RenderingContext.Deactivate;
  6257. end;
  6258. end;
  6259. function TgxSceneBuffer.WorldToScreen(const aPoint: TVector4f): TVector4f;
  6260. begin
  6261. SetVector(Result, WorldToScreen(AffineVectorMake(aPoint)));
  6262. end;
  6263. procedure TgxSceneBuffer.WorldToScreen(points: PVector4f; nbPoints: Integer);
  6264. var
  6265. i: Integer;
  6266. begin
  6267. if Assigned(FCamera) then
  6268. begin
  6269. for i := nbPoints - 1 downto 0 do
  6270. begin
  6271. Project(points^, RenderingContext.PipeLineTransformation.ViewProjectionMatrix^,
  6272. PHomogeneousIntVector(@FViewPort)^, points^);
  6273. Inc(points);
  6274. end;
  6275. end;
  6276. end;
  6277. function TgxSceneBuffer.ScreenToVector(const aPoint: TAffineVector): TAffineVector;
  6278. begin
  6279. Result := VectorSubtract(ScreenToWorld(aPoint), PAffineVector(@FCameraAbsolutePosition)^);
  6280. end;
  6281. function TgxSceneBuffer.ScreenToVector(const aPoint: TVector4f): TVector4f;
  6282. begin
  6283. SetVector(Result, VectorSubtract(ScreenToWorld(aPoint), FCameraAbsolutePosition));
  6284. Result.W := 0;
  6285. end;
  6286. function TgxSceneBuffer.ScreenToVector(const x, y: Integer): TVector4f;
  6287. var
  6288. av: TAffineVector;
  6289. begin
  6290. av.x := x;
  6291. av.y := y;
  6292. av.z := 0;
  6293. SetVector(Result, ScreenToVector(av));
  6294. end;
  6295. function TgxSceneBuffer.VectorToScreen(const VectToCam: TAffineVector): TAffineVector;
  6296. begin
  6297. Result := WorldToScreen(VectorAdd(VectToCam, PAffineVector(@FCameraAbsolutePosition)^));
  6298. end;
  6299. function TgxSceneBuffer.ScreenVectorIntersectWithPlane(const aScreenPoint: TVector4f; const planePoint, planeNormal: TVector4f;
  6300. var intersectPoint: TVector4f): Boolean;
  6301. var
  6302. v: TVector4f;
  6303. begin
  6304. if Assigned(FCamera) then
  6305. begin
  6306. SetVector(v, ScreenToVector(aScreenPoint));
  6307. Result := RayCastPlaneIntersect(FCameraAbsolutePosition, v, planePoint, planeNormal, @intersectPoint);
  6308. intersectPoint.W := 1;
  6309. end
  6310. else
  6311. Result := False;
  6312. end;
  6313. function TgxSceneBuffer.ScreenVectorIntersectWithPlaneXY(const aScreenPoint: TVector4f; const z: Single;
  6314. var intersectPoint: TVector4f): Boolean;
  6315. begin
  6316. Result := ScreenVectorIntersectWithPlane(aScreenPoint, VectorMake(0, 0, z), ZHmgVector, intersectPoint);
  6317. intersectPoint.W := 0;
  6318. end;
  6319. function TgxSceneBuffer.ScreenVectorIntersectWithPlaneYZ(const aScreenPoint: TVector4f; const x: Single;
  6320. var intersectPoint: TVector4f): Boolean;
  6321. begin
  6322. Result := ScreenVectorIntersectWithPlane(aScreenPoint, VectorMake(x, 0, 0), XHmgVector, intersectPoint);
  6323. intersectPoint.W := 0;
  6324. end;
  6325. function TgxSceneBuffer.ScreenVectorIntersectWithPlaneXZ(const aScreenPoint: TVector4f; const y: Single;
  6326. var intersectPoint: TVector4f): Boolean;
  6327. begin
  6328. Result := ScreenVectorIntersectWithPlane(aScreenPoint, VectorMake(0, y, 0), YHmgVector, intersectPoint);
  6329. intersectPoint.W := 0;
  6330. end;
  6331. function TgxSceneBuffer.PixelRayToWorld(x, y: Integer): TAffineVector;
  6332. var
  6333. dov, np, fp, z, dst, wrpdst: Single;
  6334. vec, cam, targ, rayhit, pix: TAffineVector;
  6335. camAng: real;
  6336. begin
  6337. if Camera.CameraStyle = csOrtho2D then
  6338. dov := 2
  6339. else
  6340. dov := Camera.DepthOfView;
  6341. np := Camera.NearPlane;
  6342. fp := Camera.NearPlane + dov;
  6343. z := GetPixelDepth(x, y);
  6344. dst := (fp * np) / (fp - z * dov); // calc from z-buffer value to world depth
  6345. // ------------------------
  6346. // z:=1-(fp/d-1)/(fp/np-1); //calc from world depth to z-buffer value
  6347. // ------------------------
  6348. vec.x := x;
  6349. vec.y := FViewPort.height - y;
  6350. vec.z := 0;
  6351. vec := ScreenToVector(vec);
  6352. NormalizeVector(vec);
  6353. SetVector(cam, Camera.AbsolutePosition);
  6354. // targ:=Camera.TargetObject.Position.AsAffineVector;
  6355. // SubtractVector(targ,cam);
  6356. pix.x := FViewPort.width * 0.5;
  6357. pix.y := FViewPort.height * 0.5;
  6358. pix.z := 0;
  6359. targ := Self.ScreenToVector(pix);
  6360. camAng := VectorAngleCosine(targ, vec);
  6361. wrpdst := dst / camAng;
  6362. rayhit := cam;
  6363. CombineVector(rayhit, vec, wrpdst);
  6364. Result := rayhit;
  6365. end;
  6366. procedure TgxSceneBuffer.ClearBuffers;
  6367. var
  6368. bufferBits: GLbitfield;
  6369. begin
  6370. if roNoDepthBufferClear in ContextOptions then
  6371. bufferBits := 0
  6372. else
  6373. begin
  6374. bufferBits := GL_DEPTH_BUFFER_BIT;
  6375. CurrentContext.gxStates.DepthWriteMask := True;
  6376. end;
  6377. if ContextOptions * [roNoColorBuffer, roNoColorBufferClear] = [] then
  6378. begin
  6379. bufferBits := bufferBits or GL_COLOR_BUFFER_BIT;
  6380. CurrentContext.gxStates.SetColorMask(cAllColorComponents);
  6381. end;
  6382. if roStencilBuffer in ContextOptions then
  6383. begin
  6384. bufferBits := bufferBits or GL_STENCIL_BUFFER_BIT;
  6385. end;
  6386. if bufferBits <> 0 then
  6387. glClear(bufferBits);
  6388. end;
  6389. procedure TgxSceneBuffer.NotifyChange(Sender: TObject);
  6390. begin
  6391. DoChange;
  6392. end;
  6393. procedure TgxSceneBuffer.PickObjects(const rect: TRect; pickList: TgxPickList; objectCountGuess: Integer);
  6394. var
  6395. i: Integer;
  6396. obj: TgxBaseSceneObject;
  6397. begin
  6398. if not Assigned(FCamera) then
  6399. Exit;
  6400. Assert((not FRendering), strAlreadyRendering);
  6401. Assert(Assigned(pickList));
  6402. FRenderingContext.Activate;
  6403. FRendering := True;
  6404. try
  6405. // Creates best selector which techniques is hardware can do
  6406. if not Assigned(FSelector) then
  6407. FSelector := GetBestSelectorClass.Create;
  6408. xglMapTexCoordToNull; // turn off
  6409. PrepareRenderingMatrices(FViewPort, RenderDPI, @rect);
  6410. FSelector.Hits := -1;
  6411. if objectCountGuess > 0 then
  6412. FSelector.objectCountGuess := objectCountGuess;
  6413. repeat
  6414. FSelector.Start;
  6415. // render the scene (in select mode, nothing is drawn)
  6416. FRenderDPI := 96;
  6417. if Assigned(FCamera) and Assigned(FCamera.FScene) then
  6418. RenderScene(FCamera.FScene, FViewPort.width, FViewPort.height, dsPicking, nil);
  6419. until FSelector.Stop;
  6420. FSelector.FillPickingList(pickList);
  6421. for i := 0 to pickList.Count - 1 do
  6422. begin
  6423. obj := TgxBaseSceneObject(pickList[i]);
  6424. if Assigned(obj.FOnPicked) then
  6425. obj.FOnPicked(obj);
  6426. end;
  6427. finally
  6428. FRendering := False;
  6429. FRenderingContext.Deactivate;
  6430. end;
  6431. end;
  6432. function TgxSceneBuffer.GetPickedObjects(const rect: TRect; objectCountGuess: Integer = 64): TgxPickList;
  6433. begin
  6434. Result := TgxPickList.Create(psMinDepth);
  6435. PickObjects(rect, Result, objectCountGuess);
  6436. end;
  6437. function TgxSceneBuffer.GetPickedObject(x, y: Integer): TgxBaseSceneObject;
  6438. var
  6439. pkList: TgxPickList;
  6440. begin
  6441. pkList := GetPickedObjects(rect(x - 1, y - 1, x + 1, y + 1));
  6442. try
  6443. if pkList.Count > 0 then
  6444. Result := TgxBaseSceneObject(pkList.Hit[0])
  6445. else
  6446. Result := nil;
  6447. finally
  6448. pkList.Free;
  6449. end;
  6450. end;
  6451. function TgxSceneBuffer.GetPixelColor(x, y: Integer): TColor;
  6452. var
  6453. buf: array [0 .. 2] of Byte;
  6454. begin
  6455. if not Assigned(FCamera) then
  6456. begin
  6457. Result := 0;
  6458. Exit;
  6459. end;
  6460. FRenderingContext.Activate;
  6461. try
  6462. glReadPixels(x, FViewPort.height - y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, @buf[0]);
  6463. finally
  6464. FRenderingContext.Deactivate;
  6465. end;
  6466. Result := RGB(buf[0], buf[1], buf[2]);
  6467. end;
  6468. function TgxSceneBuffer.GetPixelDepth(x, y: Integer): Single;
  6469. begin
  6470. if not Assigned(FCamera) then
  6471. begin
  6472. Result := 0;
  6473. Exit;
  6474. end;
  6475. FRenderingContext.Activate;
  6476. try
  6477. glReadPixels(x, FViewPort.height - y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, @Result);
  6478. finally
  6479. FRenderingContext.Deactivate;
  6480. end;
  6481. end;
  6482. function TgxSceneBuffer.PixelDepthToDistance(aDepth: Single): Single;
  6483. var
  6484. dov, np, fp: Single;
  6485. begin
  6486. if Camera.CameraStyle = csOrtho2D then
  6487. dov := 2
  6488. else
  6489. dov := Camera.DepthOfView; // Depth of View (from np to fp)
  6490. np := Camera.NearPlane; // Near plane distance
  6491. fp := np + dov; // Far plane distance
  6492. Result := (fp * np) / (fp - aDepth * dov);
  6493. // calculate world distance from z-buffer value
  6494. end;
  6495. function TgxSceneBuffer.PixelToDistance(x, y: Integer): Single;
  6496. var
  6497. z, dov, np, fp, dst, camAng: Single;
  6498. norm, coord, vec: TAffineVector;
  6499. begin
  6500. z := GetPixelDepth(x, y);
  6501. if Camera.CameraStyle = csOrtho2D then
  6502. dov := 2
  6503. else
  6504. dov := Camera.DepthOfView; // Depth of View (from np to fp)
  6505. np := Camera.NearPlane; // Near plane distance
  6506. fp := np + dov; // Far plane distance
  6507. dst := (np * fp) / (fp - z * dov);
  6508. // calculate from z-buffer value to frustrum depth
  6509. coord.x := x;
  6510. coord.y := y;
  6511. vec := Self.ScreenToVector(coord); // get the pixel vector
  6512. coord.x := FViewPort.width div 2;
  6513. coord.y := FViewPort.height div 2;
  6514. norm := Self.ScreenToVector(coord); // get the absolute camera direction
  6515. camAng := VectorAngleCosine(norm, vec);
  6516. Result := dst / camAng; // compensate for flat frustrum face
  6517. end;
  6518. procedure TgxSceneBuffer.NotifyMouseMove(Shift: TShiftState; x, y: Single);
  6519. begin
  6520. // Nothing
  6521. end;
  6522. procedure TgxSceneBuffer.PrepareRenderingMatrices(const AViewport: TRectangle; resolution: Integer; pickingRect: PRect = nil);
  6523. begin
  6524. RenderingContext.PipeLineTransformation.IdentityAll;
  6525. // setup projection matrix
  6526. if Assigned(pickingRect) then
  6527. begin
  6528. CurrentContext.PipeLineTransformation.SetProjectionMatrix(CreatePickMatrix((pickingRect^.Left + pickingRect^.Right) div 2,
  6529. FViewPort.height - ((pickingRect^.Top + pickingRect^.Bottom) div 2), Abs(pickingRect^.Right - pickingRect^.Left),
  6530. Abs(pickingRect^.Bottom - pickingRect^.Top), TVector4i(FViewPort)));
  6531. end;
  6532. FBaseProjectionMatrix := CurrentContext.PipeLineTransformation.ProjectionMatrix^;
  6533. if Assigned(FCamera) then
  6534. begin
  6535. FCamera.Scene.FCurrentCamera := FCamera;
  6536. // apply camera perpective
  6537. FCamera.ApplyPerspective(AViewport, FViewPort.width, FViewPort.height, resolution);
  6538. // setup model view matrix
  6539. // apply camera transformation (viewpoint)
  6540. FCamera.Apply;
  6541. FCameraAbsolutePosition := FCamera.AbsolutePosition;
  6542. end;
  6543. end;
  6544. procedure TgxSceneBuffer.DoBaseRender(const AViewport: TRectangle; resolution: Integer; drawState: TGXDrawState;
  6545. baseObject: TgxBaseSceneObject);
  6546. begin
  6547. with RenderingContext.gxStates do
  6548. begin
  6549. PrepareRenderingMatrices(AViewport, resolution);
  6550. { if not ForwardContext then }
  6551. begin
  6552. xglMapTexCoordToNull; // force XGL rebind
  6553. xglMapTexCoordToMain;
  6554. end;
  6555. if Assigned(FViewerBeforeRender) and (drawState <> dsPrinting) then
  6556. FViewerBeforeRender(Self);
  6557. if Assigned(FBeforeRender) then
  6558. if Owner is TComponent then
  6559. if not(csDesigning in TComponent(Owner).ComponentState) then
  6560. FBeforeRender(Self);
  6561. if Assigned(FCamera) and Assigned(FCamera.FScene) then
  6562. begin
  6563. with FCamera.FScene do
  6564. begin
  6565. SetupLights(maxLights);
  6566. // if not ForwardContext then
  6567. begin
  6568. if FogEnable then
  6569. begin
  6570. Enable(stFog);
  6571. FogEnvironment.ApplyFog;
  6572. end
  6573. else
  6574. Disable(stFog);
  6575. end;
  6576. RenderScene(FCamera.FScene, AViewport.width, AViewport.height, drawState, baseObject);
  6577. end;
  6578. end;
  6579. if Assigned(FPostRender) then
  6580. if Owner is TComponent then
  6581. if not(csDesigning in TComponent(Owner).ComponentState) then
  6582. FPostRender(Self);
  6583. end;
  6584. Assert(Length(FViewMatrixStack) = 0, 'Unbalance Push/PopViewMatrix.');
  6585. Assert(Length(FProjectionMatrixStack) = 0, 'Unbalance Push/PopProjectionMatrix.');
  6586. end;
  6587. procedure TgxSceneBuffer.Render;
  6588. begin
  6589. Render(nil);
  6590. end;
  6591. procedure TgxSceneBuffer.Render(baseObject: TgxBaseSceneObject);
  6592. var
  6593. perfCounter, framePerf: Int64;
  6594. begin
  6595. if FRendering then
  6596. Exit;
  6597. if not Assigned(FRenderingContext) then
  6598. Exit;
  6599. if Freezed and (FFreezeBuffer <> nil) then
  6600. begin
  6601. RenderingContext.Activate;
  6602. try
  6603. RenderingContext.gxStates.ColorClearValue := ConvertWinColor(FBackgroundColor, FBackgroundAlpha);
  6604. ClearBuffers;
  6605. glMatrixMode(GL_PROJECTION);
  6606. glLoadIdentity;
  6607. glMatrixMode(GL_MODELVIEW);
  6608. glLoadIdentity;
  6609. glRasterPos2f(-1, -1);
  6610. glDrawPixels(FFreezedViewPort.width, FFreezedViewPort.height, GL_RGBA, GL_UNSIGNED_BYTE, FFreezeBuffer);
  6611. if not(roNoSwapBuffers in ContextOptions) then
  6612. RenderingContext.SwapBuffers;
  6613. finally
  6614. RenderingContext.Deactivate;
  6615. end;
  6616. Exit;
  6617. end;
  6618. QueryPerformanceCounter(framePerf);
  6619. if Assigned(FCamera) and Assigned(FCamera.FScene) then
  6620. begin
  6621. FCamera.AbsoluteMatrixAsAddress;
  6622. FCamera.FScene.AddBuffer(Self);
  6623. end;
  6624. FRendering := True;
  6625. try
  6626. FRenderingContext.Activate;
  6627. try
  6628. if FFrameCount = 0 then
  6629. QueryPerformanceCounter(FFirstPerfCounter);
  6630. FRenderDPI := 96; // default value for screen
  6631. SetupRenderingContext(FRenderingContext);
  6632. // clear the buffers
  6633. FRenderingContext.gxStates.ColorClearValue := ConvertWinColor(FBackgroundColor, FBackgroundAlpha);
  6634. ClearBuffers;
  6635. // render
  6636. DoBaseRender(FViewPort, RenderDPI, dsRendering, baseObject);
  6637. if not(roNoSwapBuffers in ContextOptions) then
  6638. RenderingContext.SwapBuffers;
  6639. // yes, calculate average frames per second...
  6640. Inc(FFrameCount);
  6641. QueryPerformanceCounter(perfCounter);
  6642. FLastFrameTime := (perfCounter - framePerf) / vCounterFrequency;
  6643. Dec(perfCounter, FFirstPerfCounter);
  6644. if perfCounter > 0 then
  6645. FFramesPerSecond := (FFrameCount * vCounterFrequency) / perfCounter;
  6646. finally
  6647. FRenderingContext.Deactivate;
  6648. end;
  6649. if Assigned(FAfterRender) and (Owner is TComponent) then
  6650. if not(csDesigning in TComponent(Owner).ComponentState) then
  6651. FAfterRender(Self);
  6652. finally
  6653. FRendering := False;
  6654. end;
  6655. end;
  6656. procedure TgxSceneBuffer.RenderScene(aScene: TgxScene; const viewPortSizeX, viewPortSizeY: Integer; drawState: TGXDrawState;
  6657. baseObject: TgxBaseSceneObject);
  6658. var
  6659. i: Integer;
  6660. rci: TgxRenderContextInfo;
  6661. rightVector: TVector4f;
  6662. begin
  6663. FAfterRenderEffects.Clear;
  6664. aScene.FCurrentBuffer := Self;
  6665. FillChar(rci, SizeOf(rci), 0);
  6666. rci.Scene := aScene;
  6667. rci.Buffer := Self;
  6668. rci.afterRenderEffects := FAfterRenderEffects;
  6669. rci.ObjectsSorting := aScene.ObjectsSorting;
  6670. rci.VisibilityCulling := aScene.VisibilityCulling;
  6671. rci.bufferFaceCull := FFaceCulling;
  6672. rci.bufferLighting := FLighting;
  6673. rci.bufferFog := FFogEnable;
  6674. rci.bufferDepthTest := FDepthTest;
  6675. rci.drawState := drawState;
  6676. rci.sceneAmbientColor := FAmbientColor.Color;
  6677. rci.primitiveMask := cAllMeshPrimitive;
  6678. with FCamera do
  6679. begin
  6680. rci.cameraPosition := FCameraAbsolutePosition;
  6681. rci.cameraDirection := FLastDirection;
  6682. NormalizeVector(rci.cameraDirection);
  6683. rci.cameraDirection.W := 0;
  6684. rightVector := VectorCrossProduct(rci.cameraDirection, Up.AsVector);
  6685. rci.cameraUp := VectorCrossProduct(rightVector, rci.cameraDirection);
  6686. NormalizeVector(rci.cameraUp);
  6687. with rci.rcci do
  6688. begin
  6689. origin := rci.cameraPosition;
  6690. clippingDirection := rci.cameraDirection;
  6691. viewPortRadius := FViewPortRadius;
  6692. nearClippingDistance := FNearPlane;
  6693. farClippingDistance := FNearPlane + FDepthOfView;
  6694. frustum := RenderingContext.PipeLineTransformation.frustum;
  6695. end;
  6696. end;
  6697. rci.viewPortSize.cx := viewPortSizeX;
  6698. rci.viewPortSize.cy := viewPortSizeY;
  6699. rci.RenderDPI := FRenderDPI;
  6700. rci.gxStates := RenderingContext.gxStates;
  6701. rci.PipeLineTransformation := RenderingContext.PipeLineTransformation;
  6702. rci.proxySubObject := False;
  6703. rci.ignoreMaterials := (roNoColorBuffer in FContextOptions) or (rci.drawState = dsPicking);
  6704. rci.amalgamating := rci.drawState = dsPicking;
  6705. rci.gxStates.SetColorWriting(not rci.ignoreMaterials);
  6706. if Assigned(FInitiateRendering) then
  6707. FInitiateRendering(Self, rci);
  6708. if aScene.InitializableObjects.Count <> 0 then
  6709. begin
  6710. // First initialize all objects and delete them from the list.
  6711. for i := aScene.InitializableObjects.Count - 1 downto 0 do
  6712. begin
  6713. aScene.InitializableObjects.Items[i].InitializeObject( { Self? } aScene, rci);
  6714. aScene.InitializableObjects.Delete(i);
  6715. end;
  6716. end;
  6717. if RenderingContext.IsPraparationNeed then
  6718. RenderingContext.PrepareHandlesData;
  6719. if baseObject = nil then
  6720. begin
  6721. aScene.Objects.Render(rci);
  6722. end
  6723. else
  6724. baseObject.Render(rci);
  6725. rci.gxStates.SetColorWriting(True);
  6726. with FAfterRenderEffects do
  6727. if Count > 0 then
  6728. for i := 0 to Count - 1 do
  6729. TgxObjectAfterEffect(Items[i]).Render(rci);
  6730. if Assigned(FWrapUpRendering) then
  6731. FWrapUpRendering(Self, rci);
  6732. end;
  6733. procedure TgxSceneBuffer.SetBackgroundColor(AColor: TColor);
  6734. begin
  6735. if FBackgroundColor <> AColor then
  6736. begin
  6737. FBackgroundColor := AColor;
  6738. NotifyChange(Self);
  6739. end;
  6740. end;
  6741. procedure TgxSceneBuffer.SetBackgroundAlpha(alpha: Single);
  6742. begin
  6743. if FBackgroundAlpha <> alpha then
  6744. begin
  6745. FBackgroundAlpha := alpha;
  6746. NotifyChange(Self);
  6747. end;
  6748. end;
  6749. procedure TgxSceneBuffer.SetAmbientColor(AColor: TgxColor);
  6750. begin
  6751. FAmbientColor.Assign(AColor);
  6752. end;
  6753. procedure TgxSceneBuffer.SetCamera(ACamera: TgxCamera);
  6754. begin
  6755. if FCamera <> ACamera then
  6756. begin
  6757. if Assigned(FCamera) then
  6758. begin
  6759. if Assigned(FCamera.FScene) then
  6760. FCamera.FScene.RemoveBuffer(Self);
  6761. FCamera := nil;
  6762. end;
  6763. if Assigned(ACamera) and Assigned(ACamera.FScene) then
  6764. begin
  6765. FCamera := ACamera;
  6766. FCamera.TransformationChanged;
  6767. end;
  6768. NotifyChange(Self);
  6769. end;
  6770. end;
  6771. procedure TgxSceneBuffer.SetContextOptions(Options: TgxContextOptions);
  6772. begin
  6773. if FContextOptions <> Options then
  6774. begin
  6775. FContextOptions := Options;
  6776. DoStructuralChange;
  6777. end;
  6778. end;
  6779. procedure TgxSceneBuffer.SetDepthTest(aValue: Boolean);
  6780. begin
  6781. if FDepthTest <> aValue then
  6782. begin
  6783. FDepthTest := aValue;
  6784. NotifyChange(Self);
  6785. end;
  6786. end;
  6787. procedure TgxSceneBuffer.SetFaceCulling(aValue: Boolean);
  6788. begin
  6789. if FFaceCulling <> aValue then
  6790. begin
  6791. FFaceCulling := aValue;
  6792. NotifyChange(Self);
  6793. end;
  6794. end;
  6795. procedure TgxSceneBuffer.SetLayer(const Value: TgxContextLayer);
  6796. begin
  6797. if FLayer <> Value then
  6798. begin
  6799. FLayer := Value;
  6800. DoStructuralChange;
  6801. end;
  6802. end;
  6803. procedure TgxSceneBuffer.SetLighting(aValue: Boolean);
  6804. begin
  6805. if FLighting <> aValue then
  6806. begin
  6807. FLighting := aValue;
  6808. NotifyChange(Self);
  6809. end;
  6810. end;
  6811. procedure TgxSceneBuffer.SetAntiAliasing(const val: TgxAntiAliasing);
  6812. begin
  6813. if FAntiAliasing <> val then
  6814. begin
  6815. FAntiAliasing := val;
  6816. DoStructuralChange;
  6817. end;
  6818. end;
  6819. procedure TgxSceneBuffer.SetDepthPrecision(const val: TgxDepthPrecision);
  6820. begin
  6821. if FDepthPrecision <> val then
  6822. begin
  6823. FDepthPrecision := val;
  6824. DoStructuralChange;
  6825. end;
  6826. end;
  6827. procedure TgxSceneBuffer.SetColorDepth(const val: TgxColorDepth);
  6828. begin
  6829. if FColorDepth <> val then
  6830. begin
  6831. FColorDepth := val;
  6832. DoStructuralChange;
  6833. end;
  6834. end;
  6835. procedure TgxSceneBuffer.SetShadeModel(const val: TgxShadeModel);
  6836. begin
  6837. if FShadeModel <> val then
  6838. begin
  6839. FShadeModel := val;
  6840. NotifyChange(Self);
  6841. end;
  6842. end;
  6843. procedure TgxSceneBuffer.SetFogEnable(aValue: Boolean);
  6844. begin
  6845. if FFogEnable <> aValue then
  6846. begin
  6847. FFogEnable := aValue;
  6848. NotifyChange(Self);
  6849. end;
  6850. end;
  6851. procedure TgxSceneBuffer.SetFogEnvironment(aValue: TgxFogEnvironment);
  6852. begin
  6853. FFogEnvironment.Assign(aValue);
  6854. NotifyChange(Self);
  6855. end;
  6856. function TgxSceneBuffer.StoreFog: Boolean;
  6857. begin
  6858. Result := (not FFogEnvironment.IsAtDefaultValues);
  6859. end;
  6860. procedure TgxSceneBuffer.SetAccumBufferBits(const val: Integer);
  6861. begin
  6862. if FAccumBufferBits <> val then
  6863. begin
  6864. FAccumBufferBits := val;
  6865. DoStructuralChange;
  6866. end;
  6867. end;
  6868. procedure TgxSceneBuffer.DoChange;
  6869. begin
  6870. if (not FRendering) and Assigned(FOnChange) then
  6871. FOnChange(Self);
  6872. end;
  6873. procedure TgxSceneBuffer.DoStructuralChange;
  6874. var
  6875. bCall: Boolean;
  6876. begin
  6877. if Assigned(Owner) then
  6878. bCall := not(csLoading in TComponent(GetOwner).ComponentState)
  6879. else
  6880. bCall := True;
  6881. if bCall and Assigned(FOnStructuralChange) then
  6882. FOnStructuralChange(Self);
  6883. end;
  6884. // ------------------
  6885. // ------------------ TgxNonVisualViewer ------------------
  6886. // ------------------
  6887. constructor TgxNonVisualViewer.Create(AOwner: TComponent);
  6888. begin
  6889. inherited Create(AOwner);
  6890. FWidth := 256;
  6891. FHeight := 256;
  6892. FBuffer := TgxSceneBuffer.Create(Self);
  6893. FBuffer.OnChange := DoBufferChange;
  6894. FBuffer.OnStructuralChange := DoBufferStructuralChange;
  6895. FBuffer.OnPrepareGLContext := DoOnPrepareVXContext;
  6896. end;
  6897. destructor TgxNonVisualViewer.Destroy;
  6898. begin
  6899. FBuffer.Free;
  6900. inherited Destroy;
  6901. end;
  6902. procedure TgxNonVisualViewer.Notification(AComponent: TComponent; Operation: TOperation);
  6903. begin
  6904. if (Operation = opRemove) and (AComponent = Camera) then
  6905. Camera := nil;
  6906. inherited;
  6907. end;
  6908. procedure TgxNonVisualViewer.CopyToTexture(aTexture: TgxTexture);
  6909. begin
  6910. CopyToTexture(aTexture, 0, 0, width, height, 0, 0);
  6911. end;
  6912. procedure TgxNonVisualViewer.CopyToTexture(aTexture: TgxTexture; xSrc, ySrc, width, height: Integer; xDest, yDest: Integer);
  6913. begin
  6914. Buffer.CopyToTexture(aTexture, xSrc, ySrc, width, height, xDest, yDest);
  6915. end;
  6916. procedure TgxNonVisualViewer.CopyToTextureMRT(aTexture: TgxTexture; BufferIndex: Integer);
  6917. begin
  6918. CopyToTextureMRT(aTexture, 0, 0, width, height, 0, 0, BufferIndex);
  6919. end;
  6920. procedure TgxNonVisualViewer.CopyToTextureMRT(aTexture: TgxTexture; xSrc, ySrc, width, height, xDest, yDest,
  6921. BufferIndex: Integer);
  6922. var
  6923. target, Handle: Integer;
  6924. buf: Pointer;
  6925. createTexture: Boolean;
  6926. procedure CreateNewTexture;
  6927. begin
  6928. GetMem(buf, width * height * 4);
  6929. try // float_type
  6930. glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buf);
  6931. case aTexture.MinFilter of
  6932. miNearest, miLinear:
  6933. glTexImage2d(target, 0, aTexture.OpenGLTextureFormat, width, height,
  6934. 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
  6935. else
  6936. if (target = GL_TEXTURE_2D) then
  6937. begin
  6938. // hardware-accelerated when supported
  6939. glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
  6940. glTexImage2d(target, 0, aTexture.OpenGLTextureFormat, width, height,
  6941. 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
  6942. end
  6943. else
  6944. begin
  6945. glTexImage2d(target, 0, aTexture.OpenGLTextureFormat, width, height,
  6946. 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
  6947. glGenerateMipmap(target);
  6948. end;
  6949. end;
  6950. finally
  6951. FreeMem(buf);
  6952. end;
  6953. end;
  6954. begin
  6955. if Buffer.RenderingContext <> nil then
  6956. begin
  6957. Buffer.RenderingContext.Activate;
  6958. try
  6959. target := DecodeTextureTarget(aTexture.Image.NativeTextureTarget);
  6960. createTexture := True;
  6961. if aTexture.IsFloatType then
  6962. begin // float_type special treatment
  6963. createTexture := False;
  6964. Handle := aTexture.Handle;
  6965. end
  6966. else if (target <> GL_TEXTURE_CUBE_MAP_ARB) or (FCubeMapRotIdx = 0) then
  6967. begin
  6968. createTexture := not aTexture.IsHandleAllocated;
  6969. if createTexture then
  6970. Handle := aTexture.AllocateHandle
  6971. else
  6972. Handle := aTexture.Handle;
  6973. end
  6974. else
  6975. Handle := aTexture.Handle;
  6976. // For MRT
  6977. glReadBuffer(MRT_BUFFERS[BufferIndex]);
  6978. Buffer.RenderingContext.gxStates.TextureBinding[0, EncodeGLTextureTarget(target)] := Handle;
  6979. if target = GL_TEXTURE_CUBE_MAP_ARB then
  6980. target := GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + FCubeMapRotIdx;
  6981. if createTexture then
  6982. CreateNewTexture
  6983. else
  6984. glCopyTexSubImage2D(target, 0, xDest, yDest, xSrc, ySrc, width, height);
  6985. finally
  6986. Buffer.RenderingContext.Deactivate;
  6987. end;
  6988. end;
  6989. end;
  6990. procedure TgxNonVisualViewer.SetupCubeMapCamera(Sender: TObject);
  6991. (*
  6992. const
  6993. cFaceMat: array[0..5] of TGXMatrix =
  6994. (
  6995. (X: (X:0; Y:0; Z:-1; W:0);
  6996. Y: (X:0; Y:-1; Z:0; W:0);
  6997. Z: (X:-1; Y:0; Z:0; W:0);
  6998. W: (X:0; Y:0; Z:0; W:1)),
  6999. (X:(X:2.4335928828e-08; Y:0; Z:1; W:0);
  7000. Y:(X:0; Y:-1; Z:0; W:0);
  7001. Z:(X:1; Y:0; Z:-2.4335928828e-08; W:0);
  7002. W:(X:0; Y:0; Z:0; W:1)),
  7003. (X:(X:1; Y:1.2167964414e-08; Z:-1.4805936071e-16; W:0);
  7004. Y:(X:0; Y:-1.2167964414e-08; Z:-1; W:0);
  7005. Z:(X:-1.2167964414e-08; Y:1; Z:-1.2167964414e-08; W:0);
  7006. W:(X:0; Y:0; Z:0; W:1)),
  7007. (X:(X:1; Y:-1.2167964414e-08; Z:-1.4805936071e-16; W:0);
  7008. Y:(X:0; Y:-1.2167964414e-08; Z:1; W:0);
  7009. Z:(X:-1.2167964414e-08; Y:-1; Z:-1.2167964414e-08; W:0);
  7010. W:(X:0; Y:0; Z:0; W:1)),
  7011. (X:(X:1; Y:0; Z:-1.2167964414e-08; W:0);
  7012. Y:(X:0; Y:-1; Z:0; W:0);
  7013. Z:(X:-1.2167964414e-08; Y:0; Z:-1; W:0);
  7014. W:(X:0; Y:0; Z:0; W:1)),
  7015. (X:(X:-1; Y:0; Z:-1.2167964414e-08; W:0);
  7016. Y:(X:0; Y:-1; Z:0; W:0);
  7017. Z:(X:-1.2167964414e-08; Y:0; Z:1; W:0);
  7018. W:(X:0; Y:0; Z:0; W:1))
  7019. );
  7020. *)
  7021. var
  7022. TM: TMatrix4f;
  7023. begin
  7024. // Setup appropriate FOV
  7025. with CurrentContext.PipeLineTransformation do
  7026. begin
  7027. SetProjectionMatrix(CreatePerspectiveMatrix(90, 1, FCubeMapZNear, FCubeMapZFar));
  7028. TM := CreateTranslationMatrix(FCubeMapTranslation);
  7029. (* SetViewMatrix(MatrixMultiply(cFaceMat[FCubeMapRotIdx], TM)); *)
  7030. end;
  7031. end;
  7032. procedure TgxNonVisualViewer.RenderCubeMapTextures(cubeMapTexture: TgxTexture; zNear: Single = 0; zFar: Single = 0);
  7033. var
  7034. oldEvent: TNotifyEvent;
  7035. begin
  7036. Assert((width = height), 'Memory Viewer must render to a square!');
  7037. Assert(Assigned(FBuffer.FCamera), 'Camera not specified');
  7038. Assert(Assigned(cubeMapTexture), 'Texture not specified');
  7039. if zFar <= 0 then
  7040. zFar := FBuffer.FCamera.DepthOfView;
  7041. if zNear <= 0 then
  7042. zNear := zFar * 0.001;
  7043. oldEvent := FBuffer.FCamera.FDeferredApply;
  7044. FBuffer.FCamera.FDeferredApply := SetupCubeMapCamera;
  7045. FCubeMapZNear := zNear;
  7046. FCubeMapZFar := zFar;
  7047. VectorScale(FBuffer.FCamera.AbsolutePosition, -1, FCubeMapTranslation);
  7048. try
  7049. FCubeMapRotIdx := 0;
  7050. while FCubeMapRotIdx < 6 do
  7051. begin
  7052. Render;
  7053. Buffer.CopyToTexture(cubeMapTexture, 0, 0, Width, Height, 0, 0,
  7054. GL_TEXTURE_CUBE_MAP_POSITIVE_X + FCubeMapRotIdx);
  7055. Inc(FCubeMapRotIdx);
  7056. end;
  7057. finally
  7058. FBuffer.FCamera.FDeferredApply := oldEvent;
  7059. end;
  7060. end;
  7061. procedure TgxNonVisualViewer.SetBeforeRender(const val: TNotifyEvent);
  7062. begin
  7063. FBuffer.BeforeRender := val;
  7064. end;
  7065. function TgxNonVisualViewer.GetBeforeRender: TNotifyEvent;
  7066. begin
  7067. Result := FBuffer.BeforeRender;
  7068. end;
  7069. procedure TgxNonVisualViewer.SetPostRender(const val: TNotifyEvent);
  7070. begin
  7071. FBuffer.PostRender := val;
  7072. end;
  7073. function TgxNonVisualViewer.GetPostRender: TNotifyEvent;
  7074. begin
  7075. Result := FBuffer.PostRender;
  7076. end;
  7077. procedure TgxNonVisualViewer.SetAfterRender(const val: TNotifyEvent);
  7078. begin
  7079. FBuffer.AfterRender := val;
  7080. end;
  7081. function TgxNonVisualViewer.GetAfterRender: TNotifyEvent;
  7082. begin
  7083. Result := FBuffer.AfterRender;
  7084. end;
  7085. procedure TgxNonVisualViewer.SetCamera(const val: TgxCamera);
  7086. begin
  7087. FBuffer.Camera := val;
  7088. end;
  7089. function TgxNonVisualViewer.GetCamera: TgxCamera;
  7090. begin
  7091. Result := FBuffer.Camera;
  7092. end;
  7093. procedure TgxNonVisualViewer.SetBuffer(const val: TgxSceneBuffer);
  7094. begin
  7095. FBuffer.Assign(val);
  7096. end;
  7097. procedure TgxNonVisualViewer.DoOnPrepareVXContext(Sender: TObject);
  7098. begin
  7099. PrepareVXContext;
  7100. end;
  7101. procedure TgxNonVisualViewer.PrepareVXContext;
  7102. begin
  7103. // nothing, reserved for subclasses
  7104. end;
  7105. procedure TgxNonVisualViewer.DoBufferChange(Sender: TObject);
  7106. begin
  7107. // nothing, reserved for subclasses
  7108. end;
  7109. procedure TgxNonVisualViewer.DoBufferStructuralChange(Sender: TObject);
  7110. begin
  7111. FBuffer.DestroyRC;
  7112. end;
  7113. procedure TgxNonVisualViewer.SetWidth(const val: Integer);
  7114. begin
  7115. if val <> FWidth then
  7116. begin
  7117. FWidth := val;
  7118. if FWidth < 1 then
  7119. FWidth := 1;
  7120. DoBufferStructuralChange(Self);
  7121. end;
  7122. end;
  7123. procedure TgxNonVisualViewer.SetHeight(const val: Integer);
  7124. begin
  7125. if val <> FHeight then
  7126. begin
  7127. FHeight := val;
  7128. if FHeight < 1 then
  7129. FHeight := 1;
  7130. DoBufferStructuralChange(Self);
  7131. end;
  7132. end;
  7133. // ------------------
  7134. // ------------------ TgxMemoryViewer ------------------
  7135. // ------------------
  7136. constructor TgxMemoryViewer.Create(AOwner: TComponent);
  7137. begin
  7138. inherited Create(AOwner);
  7139. Width := 256;
  7140. Height := 256;
  7141. FBufferCount := 1;
  7142. end;
  7143. procedure TgxMemoryViewer.InstantiateRenderingContext;
  7144. begin
  7145. if FBuffer.RenderingContext = nil then
  7146. begin
  7147. FBuffer.SetViewPort(0, 0, Width, Height);
  7148. FBuffer.CreateRC(HWND(0), True, FBufferCount);
  7149. end;
  7150. end;
  7151. procedure TgxMemoryViewer.Render(baseObject: TgxBaseSceneObject = nil);
  7152. begin
  7153. InstantiateRenderingContext;
  7154. FBuffer.Render(baseObject);
  7155. end;
  7156. procedure TgxMemoryViewer.SetBufferCount(const Value: Integer);
  7157. const
  7158. MaxAxuBufCount = 4; // Current hardware limit = 4
  7159. begin
  7160. if FBufferCount = Value then
  7161. Exit;
  7162. FBufferCount := Value;
  7163. if FBufferCount < 1 then
  7164. FBufferCount := 1;
  7165. if FBufferCount > MaxAxuBufCount then
  7166. FBufferCount := MaxAxuBufCount;
  7167. // Request a new Instantiation of RC on next render
  7168. FBuffer.DestroyRC;
  7169. end;
  7170. // ------------------
  7171. // ------------------ TgxInitializableObjectList ------------------
  7172. // ------------------
  7173. function TgxInitializableObjectList.Add(const Item: IgxInitializable): Integer;
  7174. begin
  7175. Result := inherited Add(Pointer(Item));
  7176. end;
  7177. function TgxInitializableObjectList.GetItems(const Index: NativeInt): IgxInitializable;
  7178. begin
  7179. Result := IgxInitializable(inherited Get(Index));
  7180. end;
  7181. procedure TgxInitializableObjectList.PutItems(const Index: NativeInt; const Value: IgxInitializable);
  7182. begin
  7183. inherited Put(Index, Pointer(Value));
  7184. end;
  7185. initialization // -------------------------------------------------------------
  7186. RegisterClasses([TgxLightSource, TgxCamera, TgxProxyObject, TgxScene, TgxDirectOpenGL, TgxRenderPoint, TgxMemoryViewer]);
  7187. // preparation for high resolution timer
  7188. QueryPerformanceFrequency(vCounterFrequency);
  7189. finalization //----------------------------------------------------------------
  7190. end.