| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756775777587759776077617762776377647765776677677768776977707771777277737774777577767777777877797780778177827783778477857786778777887789779077917792779377947795779677977798779978007801780278037804780578067807780878097810781178127813781478157816781778187819782078217822782378247825782678277828782978307831783278337834783578367837783878397840784178427843784478457846784778487849785078517852785378547855 |
- //
- // The graphics engine GXScene https://github.com/glscene
- //
- unit GXS.Scene;
- (* Base classes and structures *)
- interface
- {$I GLScene.Defines.inc}
- uses
- Winapi.Windows,
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.SysUtils,
- System.UITypes,
- System.Math,
- FMX.Graphics,
- FMX.Controls,
- FMX.Types,
- FMX.Dialogs,
- GXS.XOpenGL,
- GXS.XCollection,
- GXS.BaseClasses,
- GLScene.VectorTypes,
- GXS.VectorLists,
- GLScene.VectorGeometry,
- GXS.PersistentClasses,
- GXS.GeometryBB,
- GXS.ApplicationFileIO,
- GXS.TextureFormat,
- GLScene.Strings,
- GLScene.Utils,
- GXS.Context,
- GXS.Silhouette,
- GXS.PipelineTransformation,
- GXS.State,
- GXS.Graphics,
- GXS.Texture,
- GXS.Color,
- GXS.Coordinates,
- GXS.RenderContextInfo,
- GXS.Material,
- GXS.Selection,
- GXS.ImageUtils;
- type
- // Defines which features are taken from the master object.
- TgxProxyObjectOption = (pooEffects, pooObjects, pooTransformation);
- TgxProxyObjectOptions = set of TgxProxyObjectOption;
- TgxCameraInvarianceMode = (cimNone, cimPosition, cimOrientation);
- TgxSceneViewerMode = (svmDisabled, svmDefault, svmNavigation, svmGizmo);
- const
- cDefaultProxyOptions = [pooEffects, pooObjects, pooTransformation];
- SCENE_REVISION = '$Revision: 0306$';
- SCENE_VERSION = '2020.%s';
- type
- TgxNormalDirection = (ndInside, ndOutside);
- (* Used to describe only the changes in an object,
- which have to be reflected in the scene *)
- TObjectChange = (ocTransformation, ocAbsoluteMatrix, ocInvAbsoluteMatrix, ocStructure);
- TObjectChanges = set of TObjectChange;
- TObjectBBChange = (oBBcChild, oBBcStructure);
- TObjectBBChanges = set of TObjectBBChange;
- // Flags for design notification
- TSceneOperation = (soAdd, soRemove, soMove, soRename, soSelect, soBeginUpdate, soEndUpdate);
- (* Options for the rendering context.
- roSoftwareMode: force software rendering.
- roDoubleBuffer: enables double-buffering.
- roRenderToWindows: ignored (legacy).
- roTwoSideLighting: enables two-side lighting model.
- roStereo: enables stereo support in the driver (it needs a stereo device to test...)
- roDestinationAlpha: request an Alpha channel for the rendered output
- roNoColorBuffer: don't request a color buffer (color depth setting ignored)
- roNoColorBufferClear: do not clear the color buffer automatically, if the
- whole viewer is fully repainted each frame, this can improve framerate
- roNoSwapBuffers: don't perform RenderingContext.SwapBuffers after rendering
- roNoDepthBufferClear: do not clear the depth buffer automatically. Useful for early-z culling.
- roForwardContext: force OpenGL forward context *)
- TContextOption = (roSoftwareMode, roDoubleBuffer, roStencilBuffer,
- roRenderToWindow, roTwoSideLighting, roStereo,
- roDestinationAlpha, roNoColorBuffer, roNoColorBufferClear,
- roNoSwapBuffers, roNoDepthBufferClear, roDebugContext, roForwardContext, roOpenGL_ES2_Context);
- TContextOptions = set of TContextOption;
- // IDs for limit determination
- TLimitType = (limClipPlanes, limEvalOrder, limLights, limListNesting,
- limModelViewStack, limNameStack, limPixelMapTable, limProjectionStack,
- limTextureSize, limTextureStack, limViewportDims, limAccumAlphaBits,
- limAccumBlueBits, limAccumGreenBits, limAccumRedBits, limAlphaBits,
- limAuxBuffers, limBlueBits, limGreenBits, limRedBits, limIndexBits,
- limStereo, limDoubleBuffer, limSubpixelBits, limDepthBits, limStencilBits,
- limNbTextureUnits);
- TgxBaseSceneObject = class;
- TgxSceneObjectClass = class of TgxBaseSceneObject;
- TgxCustomSceneObject = class;
- TgxScene = class;
- TgxBehaviour = class;
- TgxBehaviourClass = class of TgxBehaviour;
- TgxBehaviours = class;
- TgxEffect = class;
- TgxEffectClass = class of TgxEffect;
- TgxEffects = class;
- TgxSceneBuffer = class;
- (* Possible styles/options for objects.
- Allowed styles are:
- osDirectDraw : object shall not make use of compiled call lists, but issue
- direct calls each time a render should be performed.
- osIgnoreDepthBuffer : object is rendered with depth test disabled,
- this is true for its children too.
- osNoVisibilityCulling : whatever the VisibilityCulling setting,
- it will be ignored and the object rendered *)
- TgxObjectStyle = (
- osDirectDraw,
- osIgnoreDepthBuffer,
- osNoVisibilityCulling);
- TgxObjectStyles = set of TgxObjectStyle;
- // Interface to objects that need initialization
- IgxInitializable = interface
- ['{EA40AE8E-79B3-42F5-ADF2-7A901B665E12}']
- procedure InitializeObject(ASender: TObject; const ARci: TgxRenderContextInfo);
- end;
- // Just a list of objects that support IGLInitializable.
- TgxInitializableObjectList = class(TList)
- private
- function GetItems(const Index: Integer): IgxInitializable;
- procedure PutItems(const Index: Integer; const Value: IgxInitializable);
- public
- function Add(const Item: IgxInitializable): Integer;
- property Items[const Index: Integer]: IgxInitializable read GetItems write PutItems; default;
- end;
- (* Base class for all scene objects.
- A scene object is part of scene hierarchy (each scene object can have
- multiple children), this hierarchy primarily defines transformations
- (each child coordinates are relative to its parent), but is also used
- for depth-sorting, bounding and visibility culling purposes.
- Subclasses implement either visual scene objects (that are made to be
- visible at runtime, like a Cube) or structural objects (that influence
- rendering or are used for varied structural manipulations,
- like the ProxyObject).
- To add children at runtime, use the AddNewChild method of TgxBaseSceneObject;
- other children manipulations methods and properties are provided (to browse,
- move and delete them). Using the regular TComponent methods is not encouraged. *)
- TgxBaseSceneObject = class(TgxCoordinatesUpdateAbleComponent)
- private
- FAbsoluteMatrix, FInvAbsoluteMatrix: TMatrix4f;
- FLocalMatrix: TMatrix4f;
- FObjectStyle: TgxObjectStyles;
- FListHandle: TgxListHandle; // created on 1st use
- FPosition: TgxCoordinates;
- FDirection, FUp: TgxCoordinates;
- FScaling: TgxCoordinates;
- FChanges: TObjectChanges;
- FParent: TgxBaseSceneObject;
- FScene: TgxScene;
- FBBChanges: TObjectBBChanges;
- FBoundingBoxPersonalUnscaled: THmgBoundingBox;
- FBoundingBoxOfChildren: THmgBoundingBox;
- FBoundingBoxIncludingChildren: THmgBoundingBox;
- FChildren: TgxPersistentObjectList; // created on 1st use
- FVisible: Boolean;
- FUpdateCount: Integer;
- FShowAxes: Boolean;
- FRotation: TgxCoordinates; // current rotation angles
- FIsCalculating: Boolean;
- FObjectsSorting: TgxObjectsSorting;
- FVisibilityCulling: TgxVisibilityCulling;
- FOnProgress: TgxProgressEvent;
- FOnAddedToParent: TNotifyEvent;
- FBehaviours: TgxBehaviours;
- FEffects: TgxEffects;
- FPickable: Boolean;
- FOnPicked: TNotifyEvent;
- FTagObject: TObject;
- FTagFloat: Single;
- objList: TgxPersistentObjectList;
- distList: TgxSingleList;
- /// FOriginalFiler: TFiler; //used to allow persistent events in behaviours & effects
- (* If somebody could look at DefineProperties, ReadBehaviours, ReadEffects
- and verify code is safe to use then it could be uncommented *)
- function Get(Index: Integer): TgxBaseSceneObject; inline;
- function GetCount: Integer; inline;
- function GetIndex: Integer; inline;
- procedure SetParent(const val: TgxBaseSceneObject); inline;
- procedure SetIndex(aValue: Integer);
- procedure SetDirection(AVector: TgxCoordinates);
- procedure SetUp(AVector: TgxCoordinates);
- function GetMatrix: PMatrix4f; inline;
- procedure SetPosition(APosition: TgxCoordinates);
- procedure SetPitchAngle(AValue: Single);
- procedure SetRollAngle(AValue: Single);
- procedure SetTurnAngle(AValue: Single);
- procedure SetRotation(aRotation: TgxCoordinates);
- function GetPitchAngle: Single; inline;
- function GetTurnAngle: Single; inline;
- function GetRollAngle: Single; inline;
- procedure SetShowAxes(AValue: Boolean);
- procedure SetScaling(AValue: TgxCoordinates);
- procedure SetObjectsSorting(const val: TgxObjectsSorting);
- procedure SetVisibilityCulling(const val: TgxVisibilityCulling);
- procedure SetBehaviours(const val: TgxBehaviours);
- function GetBehaviours: TgxBehaviours;
- procedure SetEffects(const val: TgxEffects);
- function GetEffects: TgxEffects;
- function GetAbsoluteAffineScale: TAffineVector;
- function GetAbsoluteScale: TVector4f;
- procedure SetAbsoluteAffineScale(const Value: TAffineVector);
- procedure SetAbsoluteScale(const Value: TVector4f);
- function GetAbsoluteMatrix: TMatrix4f; inline;
- procedure SetAbsoluteMatrix(const Value: TMatrix4f);
- procedure SetBBChanges(const Value: TObjectBBChanges);
- function GetDirectAbsoluteMatrix: PMatrix4f;
- function GetLocalMatrix: PMatrix4f; inline;
- protected
- procedure Loaded; override;
- procedure SetScene(const Value: TgxScene); virtual;
- procedure DefineProperties(Filer: TFiler); override;
- procedure WriteBehaviours(stream: TStream);
- procedure ReadBehaviours(stream: TStream);
- procedure WriteEffects(stream: TStream);
- procedure ReadEffects(stream: TStream);
- procedure WriteRotations(stream: TStream);
- procedure ReadRotations(stream: TStream);
- function GetVisible: Boolean; virtual;
- function GetPickable: Boolean; virtual;
- procedure SetVisible(aValue: Boolean); virtual;
- procedure SetPickable(aValue: Boolean); virtual;
- procedure SetAbsolutePosition(const v: TVector4f);
- function GetAbsolutePosition: TVector4f; inline;
- procedure SetAbsoluteUp(const v: TVector4f);
- function GetAbsoluteUp: TVector4f;
- procedure SetAbsoluteDirection(const v: TVector4f);
- function GetAbsoluteDirection: TVector4f;
- function GetAbsoluteAffinePosition: TAffineVector;
- procedure SetAbsoluteAffinePosition(const Value: TAffineVector);
- procedure SetAbsoluteAffineUp(const v: TAffineVector);
- function GetAbsoluteAffineUp: TAffineVector;
- procedure SetAbsoluteAffineDirection(const v: TAffineVector);
- function GetAbsoluteAffineDirection: TAffineVector;
- procedure RecTransformationChanged; inline;
- procedure DrawAxes(var rci: TgxRenderContextInfo; pattern: Word);
- procedure GetChildren(AProc: TGetChildProc; Root: TComponent); override;
- // Should the object be considered as blended for sorting purposes?
- function Blended: Boolean; virtual;
- procedure RebuildMatrix;
- procedure SetName(const NewName: TComponentName); override;
- procedure SetParentComponent(Value: TComponent); override;
- procedure DestroyHandle; virtual;
- procedure DestroyHandles;
- procedure DeleteChildCameras;
- procedure DoOnAddedToParent; virtual;
- (* Used to re-calculate BoundingBoxes every time we need it.
- GetLocalUnscaleBB() must return the local BB, not the axis-aligned one.
- By default it is calculated from AxisAlignedBoundingBoxUnscaled and
- BarycenterAbsolutePosition, but for most objects there is a more
- efficient method, that's why it is virtual. *)
- procedure CalculateBoundingBoxPersonalUnscaled(var ANewBoundingBox: THmgBoundingBox); virtual;
- public
- constructor Create(AOwner: TComponent); override;
- constructor CreateAsChild(aParentOwner: TgxBaseSceneObject);
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- (* Controls and adjusts internal optimizations based on object's style.
- Advanced user only. *)
- property ObjectStyle: TgxObjectStyles read FObjectStyle write FObjectStyle;
- (* Returns the handle to the object's build list.
- Use with caution! Some objects don't support buildlists! *)
- function GetHandle(var rci: TgxRenderContextInfo): Cardinal;
- function ListHandleAllocated: Boolean; inline;
- (* The local transformation (relative to parent).
- If you're *sure* the local matrix is up-to-date, you may use LocalMatrix
- for quicker access. *)
- procedure SetMatrix(const aValue: TMatrix4f); inline;
- property Matrix: PMatrix4f read GetMatrix;
- (* Holds the local transformation (relative to parent).
- If you're not *sure* the local matrix is up-to-date, use Matrix property. *)
- property LocalMatrix: PMatrix4f read GetLocalMatrix;
- (* Forces the local matrix to the specified value.
- AbsoluteMatrix, InverseMatrix, etc. will honour that change, but
- may become invalid if the specified matrix isn't orthonormal (can
- be used for specific rendering or projection effects).
- The local matrix will be reset by the next TransformationChanged,
- position or attitude change. *)
- procedure ForceLocalMatrix(const aMatrix: TMatrix4f); inline;
- // See AbsoluteMatrix.
- function AbsoluteMatrixAsAddress: PMatrix4f;
- (* Holds the absolute transformation matrix.
- If you're not *sure* the absolute matrix is up-to-date,
- use the AbsoluteMatrix property, this one may be nil... *)
- property DirectAbsoluteMatrix: PMatrix4f read GetDirectAbsoluteMatrix;
- (* Calculates the object's absolute inverse matrix.
- Multiplying an absolute coordinate with this matrix gives a local coordinate.
- The current implem uses transposition(AbsoluteMatrix), which is true
- unless you're using some scaling... *)
- function InvAbsoluteMatrix: TMatrix4f; inline;
- // See InvAbsoluteMatrix.
- function InvAbsoluteMatrixAsAddress: PMatrix4f;
- (* The object's absolute matrix by composing all local matrices.
- Multiplying a local coordinate with this matrix gives an absolute coordinate. *)
- property AbsoluteMatrix: TMatrix4f read GetAbsoluteMatrix write SetAbsoluteMatrix;
- // Direction vector in absolute coordinates.
- property AbsoluteDirection: TVector4f read GetAbsoluteDirection write SetAbsoluteDirection;
- property AbsoluteAffineDirection: TAffineVector read GetAbsoluteAffineDirection write SetAbsoluteAffineDirection;
- (* Scale vector in absolute coordinates.
- Warning: SetAbsoluteScale() does not work correctly at the moment. *)
- property AbsoluteScale: TVector4f read GetAbsoluteScale write SetAbsoluteScale;
- property AbsoluteAffineScale: TAffineVector read GetAbsoluteAffineScale write SetAbsoluteAffineScale;
- // Up vector in absolute coordinates.
- property AbsoluteUp: TVector4f read GetAbsoluteUp write SetAbsoluteUp;
- property AbsoluteAffineUp: TAffineVector read GetAbsoluteAffineUp write SetAbsoluteAffineUp;
- // Calculate the right vector in absolute coordinates.
- function AbsoluteRight: TVector4f;
- // Calculate the left vector in absolute coordinates.
- function AbsoluteLeft: TVector4f;
- // Computes and allows to set the object's absolute coordinates.
- property AbsolutePosition: TVector4f read GetAbsolutePosition write SetAbsolutePosition;
- property AbsoluteAffinePosition: TAffineVector read GetAbsoluteAffinePosition write SetAbsoluteAffinePosition;
- function AbsolutePositionAsAddress: PVector4f;
- // Returns the Absolute X Vector expressed in local coordinates.
- function AbsoluteXVector: TVector4f;
- // Returns the Absolute Y Vector expressed in local coordinates.
- function AbsoluteYVector: TVector4f;
- // Returns the Absolute Z Vector expressed in local coordinates.
- function AbsoluteZVector: TVector4f;
- // Converts a vector/point from absolute coordinates to local coordinates.
- function AbsoluteToLocal(const v: TVector4f): TVector4f; overload;
- // Converts a vector from absolute coordinates to local coordinates.
- function AbsoluteToLocal(const v: TAffineVector): TAffineVector; overload;
- // Converts a vector/point from local coordinates to absolute coordinates.
- function LocalToAbsolute(const v: TVector4f): TVector4f; overload;
- // Converts a vector from local coordinates to absolute coordinates.
- function LocalToAbsolute(const v: TAffineVector): TAffineVector; overload;
- // Returns the Right vector (based on Up and Direction)
- function Right: TVector4f; inline;
- // Returns the Left vector (based on Up and Direction)
- function LeftVector: TVector4f; inline;
- // Returns the Right vector (based on Up and Direction)
- function AffineRight: TAffineVector; inline;
- // Returns the Left vector (based on Up and Direction)
- function AffineLeftVector: TAffineVector; inline;
- (* Calculates the object's square distance to a point/object.
- pt is assumed to be in absolute coordinates,
- AbsolutePosition is considered as being the object position. *)
- function SqrDistanceTo(anObject: TgxBaseSceneObject): Single; overload;
- function SqrDistanceTo(const pt: TVector4f): Single; overload;
- function SqrDistanceTo(const pt: TAffineVector): Single; overload;
- (* Computes the object's distance to a point/object.
- Only objects AbsolutePositions are considered. *)
- function DistanceTo(anObject: TgxBaseSceneObject): Single; overload;
- function DistanceTo(const pt: TAffineVector): Single; overload;
- function DistanceTo(const pt: TVector4f): Single; overload;
- (* Calculates the object's barycenter in absolute coordinates.
- Default behaviour is to consider Barycenter=AbsolutePosition
- (whatever the number of children).
- SubClasses where AbsolutePosition is not the barycenter should
- override this method as it is used for distance calculation, during
- rendering for instance, and may lead to visual inconsistencies. *)
- function BarycenterAbsolutePosition: TVector4f; virtual;
- // Calculates the object's barycenter distance to a point.
- function BarycenterSqrDistanceTo(const pt: TVector4f): Single;
- (* Shall returns the object's axis aligned extensions.
- The dimensions are measured from object center and are expressed
- with scale accounted for, in the object's coordinates
- (not in absolute coordinates).
- Default value is half the object's Scale. *)
- function AxisAlignedDimensions: TVector4f; virtual;
- function AxisAlignedDimensionsUnscaled: TVector4f; virtual;
- (* Calculates and return the AABB for the object.
- The AABB is currently calculated from the BB.
- There is no caching scheme for them. *)
- function AxisAlignedBoundingBox(const AIncludeChilden: Boolean = True): TAABB;
- function AxisAlignedBoundingBoxUnscaled(const AIncludeChilden: Boolean = True): TAABB;
- function AxisAlignedBoundingBoxAbsolute(const AIncludeChilden: Boolean = True;
- const AUseBaryCenter: Boolean = False): TAABB;
- (* Advanced AABB functions that use a caching scheme.
- Also they include children and use BaryCenter. *)
- function AxisAlignedBoundingBoxEx: TAABB;
- function AxisAlignedBoundingBoxAbsoluteEx: TAABB;
- (* Calculates and return the Bounding Box for the object.
- The BB is calculated each time this method is invoked,
- based on the AxisAlignedDimensions of the object and that of its
- children. There is no caching scheme for them. *)
- function BoundingBox(const AIncludeChilden: Boolean = True; const
- AUseBaryCenter: Boolean = False): THmgBoundingBox;
- function BoundingBoxUnscaled(const AIncludeChilden: Boolean = True; const
- AUseBaryCenter: Boolean = False): THmgBoundingBox;
- function BoundingBoxAbsolute(const AIncludeChilden: Boolean = True; const
- AUseBaryCenter: Boolean = False): THmgBoundingBox;
- (* Advanced BB functions that use a caching scheme.
- Also they include children and use BaryCenter. *)
- function BoundingBoxPersonalUnscaledEx: THmgBoundingBox;
- function BoundingBoxOfChildrenEx: THmgBoundingBox;
- function BoundingBoxIncludingChildrenEx: THmgBoundingBox;
- // Max distance of corners of the BoundingBox.
- function BoundingSphereRadius: Single; inline;
- function BoundingSphereRadiusUnscaled: Single; inline;
- (* Indicates if a point is within an object.
- Given coordinate is an absolute coordinate.
- Linear or surfacic objects shall always return False.
- Default value is based on AxisAlignedDimension and a cube bounding. *)
- function PointInObject(const point: TVector4f): Boolean; virtual;
- (* Request to determine an intersection with a casted ray.
- Given coordinates & vector are in absolute coordinates, rayVector
- must be normalized.
- rayStart may be a point inside the object, allowing retrieval of
- the multiple intersects of the ray.
- When intersectXXX parameters are nil (default) implementation should
- take advantage of this to optimize calculus, if not, and an intersect
- is found, non nil parameters should be defined.
- The intersectNormal needs NOT be normalized by the implementations.
- Default value is based on bounding sphere. *)
- function RayCastIntersect(const rayStart, rayVector: TVector4f;
- intersectPoint: PVector4f = nil;
- intersectNormal: PVector4f = nil): Boolean; virtual;
- (* Request to generate silhouette outlines.
- Default implementation assumes the objects is a sphere of
- AxisAlignedDimensionUnscaled size. Subclasses may choose to return
- nil instead, which will be understood as an empty silhouette. *)
- function GenerateSilhouette(const silhouetteParameters:
- TgxSilhouetteParameters): TgxSilhouette; virtual;
- property Children[Index: Integer]: TgxBaseSceneObject read Get; default;
- property Count: Integer read GetCount;
- property Index: Integer read GetIndex write SetIndex;
- // Create a new scene object and add it to this object as new child
- function AddNewChild(AChild: TgxSceneObjectClass): TgxBaseSceneObject; virtual;
- // Create a new scene object and add it to this object as first child
- function AddNewChildFirst(AChild: TgxSceneObjectClass): TgxBaseSceneObject; virtual;
- procedure AddChild(AChild: TgxBaseSceneObject); virtual;
- function GetOrCreateBehaviour(aBehaviour: TgxBehaviourClass): TgxBehaviour;
- function AddNewBehaviour(aBehaviour: TgxBehaviourClass): TgxBehaviour;
- function GetOrCreateEffect(anEffect: TgxEffectClass): TgxEffect;
- function AddNewEffect(anEffect: TgxEffectClass): TgxEffect;
- function HasSubChildren: Boolean;
- procedure DeleteChildren; virtual;
- procedure Insert(AIndex: Integer; AChild: TgxBaseSceneObject); virtual;
- (* Takes a scene object out of the child list, but doesn't destroy it.
- If 'KeepChildren' is true its children will be kept as new children
- in this scene object. *)
- procedure Remove(AChild: TgxBaseSceneObject; keepChildren: Boolean); virtual;
- function IndexOfChild(AChild: TgxBaseSceneObject): Integer;
- function FindChild(const aName: string; ownChildrenOnly: Boolean): TgxBaseSceneObject;
- (* The "safe" version of this procedure checks if indexes are inside
- the list. If not, no exception if raised. *)
- procedure ExchangeChildrenSafe(anIndex1, anIndex2: Integer);
- (* The "regular" version of this procedure does not perform any checks
- and calls FChildren.Exchange directly. User should/can perform range
- checks manualy. *)
- procedure ExchangeChildren(anIndex1, anIndex2: Integer);
- // These procedures are safe.
- procedure MoveChildUp(anIndex: Integer);
- procedure MoveChildDown(anIndex: Integer);
- procedure MoveChildFirst(anIndex: Integer);
- procedure MoveChildLast(anIndex: Integer);
- procedure DoProgress(const progressTime: TgxProgressTimes); override;
- procedure MoveTo(newParent: TgxBaseSceneObject); virtual;
- procedure MoveUp;
- procedure MoveDown;
- procedure MoveFirst;
- procedure MoveLast;
- procedure BeginUpdate; inline;
- procedure EndUpdate; inline;
- (* Make object-specific geometry description here.
- Subclasses should MAINTAIN OpenGL states (restore the states if
- they were altered). *)
- procedure BuildList(var rci: TgxRenderContextInfo); virtual;
- function GetParentComponent: TComponent; override;
- function HasParent: Boolean; override; final;
- function IsUpdating: Boolean; inline;
- // Moves the object along the Up vector (move up/down)
- procedure Lift(ADistance: Single);
- // Moves the object along the direction vector
- procedure Move(ADistance: Single);
- // Translates the object
- procedure Translate(tx, ty, tz: Single);
- procedure MoveObjectAround(anObject: TgxBaseSceneObject; pitchDelta, turnDelta: Single);
- procedure MoveObjectAllAround(anObject: TgxBaseSceneObject; pitchDelta, turnDelta: Single);
- procedure Pitch(angle: Single);
- procedure Roll(angle: Single);
- procedure Turn(angle: Single);
- (* Sets all rotations to zero and restores default Direction/Up.
- Using this function then applying roll/pitch/turn in the order that
- suits you, you can give an "absolute" meaning to rotation angles
- (they are still applied locally though).
- Scale and Position are not affected. *)
- procedure ResetRotations;
- // Reset rotations and applies them back in the specified order.
- procedure ResetAndPitchTurnRoll(const degX, degY, degZ: Single);
- // Applies rotations around absolute X, Y and Z axis.
- procedure RotateAbsolute(const rx, ry, rz: Single); overload;
- // Applies rotations around the absolute given vector (angle in degrees).
- procedure RotateAbsolute(const axis: TAffineVector; angle: Single); overload;
- // Moves camera along the right vector (move left and right)
- procedure Slide(ADistance: Single);
- // Orients the object toward a target object
- procedure PointTo(const ATargetObject: TgxBaseSceneObject; const AUpVector: TVector4f); overload;
- // Orients the object toward a target absolute position
- procedure PointTo(const AAbsolutePosition, AUpVector: TVector4f); overload;
- procedure Render(var ARci: TgxRenderContextInfo);
- procedure DoRender(var ARci: TgxRenderContextInfo;
- ARenderSelf, ARenderChildren: Boolean); virtual;
- procedure RenderChildren(firstChildIndex, lastChildIndex: Integer;
- var rci: TgxRenderContextInfo);
- procedure StructureChanged; virtual;
- procedure ClearStructureChanged; inline;
- // Recalculate an orthonormal system
- procedure CoordinateChanged(Sender: TgxCustomCoordinates); override;
- procedure TransformationChanged; inline;
- procedure NotifyChange(Sender: TObject); override;
- property Rotation: TgxCoordinates read FRotation write SetRotation;
- property PitchAngle: Single read GetPitchAngle write SetPitchAngle;
- property RollAngle: Single read GetRollAngle write SetRollAngle;
- property TurnAngle: Single read GetTurnAngle write SetTurnAngle;
- property ShowAxes: Boolean read FShowAxes write SetShowAxes default False;
- property Changes: TObjectChanges read FChanges;
- property BBChanges: TObjectBBChanges read FBBChanges write SetBBChanges;
- property Parent: TgxBaseSceneObject read FParent write SetParent;
- property Position: TgxCoordinates read FPosition write SetPosition;
- property Direction: TgxCoordinates read FDirection write SetDirection;
- property Up: TgxCoordinates read FUp write SetUp;
- property Scale: TgxCoordinates read FScaling write SetScaling;
- property Scene: TgxScene read FScene;
- property Visible: Boolean read FVisible write SetVisible default True;
- property Pickable: Boolean read FPickable write SetPickable default True;
- property ObjectsSorting: TgxObjectsSorting read FObjectsSorting write
- SetObjectsSorting default osInherited;
- property VisibilityCulling: TgxVisibilityCulling read FVisibilityCulling
- write SetVisibilityCulling default vcInherited;
- property OnProgress: TgxProgressEvent read FOnProgress write FOnProgress;
- property OnPicked: TNotifyEvent read FOnPicked write FOnPicked;
- property OnAddedToParent: TNotifyEvent read FOnAddedToParent write FOnAddedToParent;
- property Behaviours: TgxBehaviours read GetBehaviours write SetBehaviours stored False;
- property Effects: TgxEffects read GetEffects write SetEffects stored False;
- property TagObject: TObject read FTagObject write FTagObject;
- published
- property TagFloat: Single read FTagFloat write FTagFloat;
- end;
- (* Base class for implementing behaviours in TgxScene.
- Behaviours are regrouped in a collection attached to a TgxBaseSceneObject,
- and are part of the "Progress" chain of events. Behaviours allows clean
- application of time-based alterations to objects (movements, shape or
- texture changes...).
- Since behaviours are implemented as classes, there are basicly two kinds
- of strategies for subclasses :
- stand-alone : the subclass does it all, and holds all necessary data
- (covers animation, inertia etc.)
- proxy : the subclass is an interface to and external, shared operator
- (like gravity, force-field effects etc.)
- Some behaviours may be cooperative (like force-fields affects inertia)
- or unique (e.g. only one inertia behaviour per object).
- NOTES : Don't forget to override the ReadFromFiler/WriteToFiler persistence
- methods if you add data in a subclass !
- Subclasses must be registered using the RegisterXCollectionItemClass function *)
- TgxBaseBehaviour = class(TXCollectionItem)
- protected
- procedure SetName(const val: string); override;
- // Override this function to write subclass data.
- procedure WriteToFiler(writer: TWriter); override;
- // Override this function to read subclass data.
- procedure ReadFromFiler(reader: TReader); override;
- (* Returns the TgxBaseSceneObject on which the behaviour should be applied.
- Does NOT check for nil owners. *)
- function OwnerBaseSceneObject: TgxBaseSceneObject;
- public
- constructor Create(AOwner: TXCollection); override;
- destructor Destroy; override;
- procedure DoProgress(const progressTime: TgxProgressTimes); virtual;
- end;
- (* Ancestor for non-rendering behaviours.
- This class shall never receive any properties, it's just here to differentiate
- rendereing and non-rendering behaviours. Rendereing behaviours are named
- "TgxEffect", non-rendering effects (like inertia) are simply named
- "TgxBehaviour". *)
- TgxBehaviour = class(TgxBaseBehaviour)
- end;
- (* Holds a list of TgxBehaviour objects.
- This object expects itself to be owned by a TgxBaseSceneObject.
- As a TXCollection (and contrary to a TCollection), this list can contain
- objects of varying class, the only constraint being that they should all
- be TgxBehaviour subclasses. *)
- TgxBehaviours = class(TXCollection)
- protected
- function GetBehaviour(Index: Integer): TgxBehaviour;
- public
- constructor Create(AOwner: TPersistent); override;
- function GetNamePath: string; override;
- class function ItemsClass: TXCollectionItemClass; override;
- property Behaviour[index: Integer]: TgxBehaviour read GetBehaviour; default;
- function CanAdd(aClass: TXCollectionItemClass): Boolean; override;
- procedure DoProgress(const progressTimes: TgxProgressTimes); inline;
- end;
- (* A rendering effect that can be applied to SceneObjects.
- ObjectEffect is a subclass of behaviour that gets a chance to Render
- an object-related special effect.
- TgxEffect should not be used as base class for custom effects,
- instead you should use the following base classes :
- TgxObjectPreEffect is rendered before owner object render
- TgxObjectPostEffect is rendered after the owner object render
- TgxObjectAfterEffect is rendered at the end of the scene rendering
- NOTES :
- Don't forget to override the ReadFromFiler/WriteToFiler persistence
- methods if you add data in a subclass !
- Subclasses must be registered using the RegisterXCollectionItemClass
- function *)
- // TgxEffectClass = class of TgxEffect;
- TgxEffect = class(TgxBaseBehaviour)
- protected
- // Override this function to write subclass data.
- procedure WriteToFiler(writer: TWriter); override;
- // Override this function to read subclass data.
- procedure ReadFromFiler(reader: TReader); override;
- public
- procedure Render(var rci: TgxRenderContextInfo); virtual;
- end;
- (* An object effect that gets rendered before owner object's render.
- The current OpenGL matrices and material are that of the owner object. *)
- TgxObjectPreEffect = class(TgxEffect)
- end;
- (* An object effect that gets rendered after owner object's render.
- The current OpenGL matrices and material are that of the owner object. *)
- TgxObjectPostEffect = class(TgxEffect)
- end;
- (* An object effect that gets rendered at scene's end.
- No particular OpenGL matrices or material should be assumed. *)
- TgxObjectAfterEffect = class(TgxEffect)
- end;
- (* Holds a list of object effects.
- This object expects itself to be owned by a TgxBaseSceneObject. *)
- TgxEffects = class(TXCollection)
- protected
- function GetEffect(Index: Integer): TgxEffect;
- public
- constructor Create(AOwner: TPersistent); override;
- function GetNamePath: string; override;
- class function ItemsClass: TXCollectionItemClass; override;
- property ObjectEffect[index: Integer]: TgxEffect read GetEffect; default;
- function CanAdd(aClass: TXCollectionItemClass): Boolean; override;
- procedure DoProgress(const progressTime: TgxProgressTimes);
- procedure RenderPreEffects(var rci: TgxRenderContextInfo); inline;
- // Also take care of registering after effects with the GLXceneViewer.
- procedure RenderPostEffects(var rci: TgxRenderContextInfo); inline;
- end;
- (* Extended base scene object class with a material property.
- The material allows defining a color and texture for the object, see TgxMaterial. *)
- TgxCustomSceneObject = class(TgxBaseSceneObject)
- private
- FMaterial: TgxMaterial;
- FHint: string;
- protected
- function Blended: Boolean; override;
- procedure SetVKMaterial(aValue: TgxMaterial); inline;
- procedure DestroyHandle; override;
- procedure Loaded; override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
- property Material: TgxMaterial read FMaterial write SetVKMaterial;
- property Hint: string read FHint write FHint;
- end;
- (* This class shall be used only as a hierarchy root.
- It exists only as a container and shall never be rotated/scaled etc. as
- the class type is used in parenting optimizations.
- Shall never implement or add any functionality, the "Create" override
- only take cares of disabling the build list. *)
- TgxSceneRootObject = class(TgxBaseSceneObject)
- public
- constructor Create(AOwner: TComponent); override;
- end;
- (* Base class for objects that do not have a published "material".
- Note that the material is available in public properties, but isn't
- applied automatically before invoking BuildList.
- Subclassing should be reserved to structural objects and objects that
- have no material of their own. *)
- TgxImmaterialSceneObject = class(TgxCustomSceneObject)
- public
- procedure DoRender(var ARci: TgxRenderContextInfo;
- ARenderSelf, ARenderChildren: Boolean); override;
- published
- property ObjectsSorting;
- property VisibilityCulling;
- property Direction;
- property PitchAngle;
- property Position;
- property RollAngle;
- property Scale;
- property ShowAxes;
- property TurnAngle;
- property Up;
- property Visible;
- property Pickable;
- property OnProgress;
- property OnPicked;
- property Behaviours;
- property Effects;
- property Hint;
- end;
- (* Base class for camera invariant objects.
- Camera invariant objects bypass camera settings, such as camera
- position (object is always centered on camera) or camera orientation
- (object always has same orientation as camera). *)
- TgxCameraInvariantObject = class(TgxImmaterialSceneObject)
- private
- FCamInvarianceMode: TgxCameraInvarianceMode;
- protected
- procedure SetCamInvarianceMode(const val: TgxCameraInvarianceMode);
- property CamInvarianceMode: TgxCameraInvarianceMode read FCamInvarianceMode
- write SetCamInvarianceMode;
- public
- constructor Create(AOwner: TComponent); override;
- procedure Assign(Source: TPersistent); override;
- procedure DoRender(var ARci: TgxRenderContextInfo;
- ARenderSelf, ARenderChildren: Boolean); override;
- end;
- // Base class for standard scene objects. Publishes the Material property.
- TgxSceneObject = class(TgxCustomSceneObject)
- published
- property Material;
- property ObjectsSorting;
- property VisibilityCulling;
- property Direction;
- property PitchAngle;
- property Position;
- property RollAngle;
- property Scale;
- property ShowAxes;
- property TurnAngle;
- property Up;
- property Visible;
- property Pickable;
- property OnProgress;
- property OnPicked;
- property Behaviours;
- property Effects;
- property Hint;
- end;
- // Event for user-specific rendering in a TgxDirectOpenVX object.
- TDirectRenderEvent = procedure(Sender: TObject; var rci: TgxRenderContextInfo) of object;
- (* Provides a way to issue direct OpenGL calls during the rendering.
- You can use this object to do your specific rendering task in its OnRender
- event. The OpenGL calls shall restore the OpenGL states they found when
- entering, or exclusively use the GLMisc utility functions to alter the states. *)
- TgxDirectOpenGL = class(TgxImmaterialSceneObject)
- private
- FUseBuildList: Boolean;
- FOnRender: TDirectRenderEvent;
- FBlend: Boolean;
- protected
- procedure SetUseBuildList(const val: Boolean);
- function Blended: Boolean; override;
- procedure SetBlend(const val: Boolean);
- public
- constructor Create(AOwner: TComponent); override;
- procedure Assign(Source: TPersistent); override;
- procedure BuildList(var rci: TgxRenderContextInfo); override;
- function AxisAlignedDimensionsUnscaled: TVector4f; override;
- published
- (* Specifies if a build list be made.
- If True, GXScene will generate a build list (side cache),
- ie. OnRender will only be invoked once for the first render, or after
- a StructureChanged call. This is suitable for "static" geometry and
- will usually speed up rendering of things that don't change.
- If false, OnRender will be invoked for each render. This is suitable
- for dynamic geometry (things that change often or constantly). *)
- property UseBuildList: Boolean read FUseBuildList write SetUseBuildList;
- (* Place your specific OpenGL code here.
- The OpenGL calls shall restore the OpenGL states they found when
- entering, or exclusively use the GLMisc utility functions to alter
- the states. *)
- property OnRender: TDirectRenderEvent read FOnRender write FOnRender;
- (* Defines if the object uses blending.
- This property will allow direct OpenGL objects to be flagged as
- blended for object sorting purposes. *)
- property Blend: Boolean read FBlend write SetBlend;
- end;
- (* Scene object that allows other objects to issue rendering at some point.
- This object is used to specify a render point for which other components
- have (rendering) tasks to perform. It doesn't render anything itself
- and is invisible, but other components can register and be notified
- when the point is reached in the rendering phase.
- Callbacks must be explicitly unregistered. *)
- TgxRenderPoint = class(TgxImmaterialSceneObject)
- private
- FCallBacks: array of TDirectRenderEvent;
- FFreeCallBacks: array of TNotifyEvent;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure BuildList(var rci: TgxRenderContextInfo); override;
- procedure RegisterCallBack(renderEvent: TDirectRenderEvent;
- renderPointFreed: TNotifyEvent);
- procedure UnRegisterCallBack(renderEvent: TDirectRenderEvent);
- procedure Clear;
- end;
- (* A full proxy object.
- This object literally uses another object's Render method to do its own
- rendering, however, it has a coordinate system and a life of its own.
- Use it for duplicates of an object. *)
- TgxProxyObject = class(TgxBaseSceneObject)
- private
- FMasterObject: TgxBaseSceneObject;
- FProxyOptions: TgxProxyObjectOptions;
- protected
- FRendering: Boolean;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure SetMasterObject(const val: TgxBaseSceneObject); virtual;
- procedure SetProxyOptions(const val: TgxProxyObjectOptions);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
- function BarycenterAbsolutePosition: TVector4f; override;
- function AxisAlignedDimensions: TVector4f; override;
- function AxisAlignedDimensionsUnscaled: TVector4f; override;
- function RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil)
- : Boolean; override;
- function GenerateSilhouette(const SilhouetteParameters: TgxSilhouetteParameters): TgxSilhouette; override;
- published
- // Specifies the Master object which will be proxy'ed.
- property MasterObject: TgxBaseSceneObject read FMasterObject write SetMasterObject;
- // Specifies how and what is proxy'ed.
- property ProxyOptions: TgxProxyObjectOptions read FProxyOptions write SetProxyOptions default cDefaultProxyOptions;
- property ObjectsSorting;
- property Direction;
- property PitchAngle;
- property Position;
- property RollAngle;
- property Scale;
- property ShowAxes;
- property TurnAngle;
- property Up;
- property Visible;
- property Pickable;
- property OnProgress;
- property OnPicked;
- property Behaviours;
- end;
- TgxProxyObjectClass = class of TgxProxyObject;
- (* Defines the various styles for lightsources.
- lsSpot : a spot light, oriented and with a cutoff zone (note that if
- cutoff is 180, the spot is rendered as an omni source)
- lsOmni : an omnidirectionnal source, punctual and sending light in
- all directions uniformously
- lsParallel : a parallel light, oriented as the light source is (this
- type of light can help speed up rendering) *)
- TgxLightStyle = (lsSpot, lsOmni, lsParallel, lsParallelSpot);
- (* Standard light source.
- The standard light source covers spotlights, omnidirectionnal and
- parallel sources (see TLightStyle).
- Lights are colored, have distance attenuation parameters and are turned
- on/off through their Shining property.
- Lightsources are managed in a specific object by the TgxScene for rendering
- purposes. The maximum number of light source in a scene is limited by the
- OpenGL implementation (8 lights are supported under most ICDs), though the
- more light you use, the slower rendering may get. If you want to render
- many more light/lightsource, you may have to resort to other techniques
- like lightmapping. *)
- TgxLightSource = class(TgxBaseSceneObject)
- private
- FLightID: Cardinal;
- FSpotDirection: TgxCoordinates;
- FSpotExponent, FSpotCutOff: Single;
- FConstAttenuation, FLinearAttenuation, FQuadraticAttenuation: Single;
- FShining: Boolean;
- FAmbient, FDiffuse, FSpecular: TgxColor;
- FLightStyle: TgxLightStyle;
- protected
- procedure SetAmbient(aValue: TgxColor);
- procedure SetDiffuse(aValue: TgxColor);
- procedure SetSpecular(aValue: TgxColor);
- procedure SetConstAttenuation(aValue: Single);
- procedure SetLinearAttenuation(aValue: Single);
- procedure SetQuadraticAttenuation(aValue: Single);
- procedure SetShining(aValue: Boolean);
- procedure SetSpotDirection(AVector: TgxCoordinates);
- procedure SetSpotExponent(aValue: Single);
- procedure SetSpotCutOff(const val: Single);
- procedure SetLightStyle(const val: TgxLightStyle);
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
- // light sources have different handle types than normal scene objects
- function RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil)
- : Boolean; override;
- procedure CoordinateChanged(Sender: TgxCustomCoordinates); override;
- function GenerateSilhouette(const silhouetteParameters: TgxSilhouetteParameters): TgxSilhouette; override;
- property LightID: Cardinal read FLightID;
- function Attenuated: Boolean;
- published
- property Ambient: TgxColor read FAmbient write SetAmbient;
- property ConstAttenuation: Single read FConstAttenuation write SetConstAttenuation;
- property Diffuse: TgxColor read FDiffuse write SetDiffuse;
- property LinearAttenuation: Single read FLinearAttenuation write SetLinearAttenuation;
- property QuadraticAttenuation: Single read FQuadraticAttenuation write SetQuadraticAttenuation;
- property Position;
- property LightStyle: TgxLightStyle read FLightStyle write SetLightStyle default lsSpot;
- property Shining: Boolean read FShining write SetShining default True;
- property Specular: TgxColor read FSpecular write SetSpecular;
- property SpotCutOff: Single read FSpotCutOff write SetSpotCutOff;
- property SpotDirection: TgxCoordinates read FSpotDirection write SetSpotDirection;
- property SpotExponent: Single read FSpotExponent write SetSpotExponent;
- property OnProgress;
- end;
- TgxCameraStyle = (csPerspective, csOrthogonal, csOrtho2D, csCustom, csInfinitePerspective, csPerspectiveKeepFOV);
- TgxCameraKeepFOVMode = (ckmHorizontalFOV, ckmVerticalFOV);
- TOnCustomPerspective = procedure(const viewport: TRectangle; width, height: Integer; DPI: Integer; var viewPortRadius: Single)
- of object;
- (* Camera object.
- This object is commonly referred by TgxSceneViewer and defines a position,
- direction, focal length, depth of view... all the properties needed for
- defining a point of view and optical characteristics. *)
- TgxCamera = class(TgxBaseSceneObject)
- private
- FFocalLength: Single;
- FDepthOfView: Single;
- FNearPlane: Single; // nearest distance to the camera
- FNearPlaneBias: Single; // scaling bias applied to near plane
- FViewPortRadius: Single; // viewport bounding radius per distance unit
- FTargetObject: TgxBaseSceneObject;
- FLastDirection: TVector4f; // Not persistent
- FCameraStyle: TgxCameraStyle;
- FKeepFOVMode: TgxCameraKeepFOVMode;
- FSceneScale: Single;
- FDeferredApply: TNotifyEvent;
- FOnCustomPerspective: TOnCustomPerspective;
- FDesign: Boolean;
- FFOVY, FFOVX: Double;
- protected
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure SetTargetObject(const val: TgxBaseSceneObject);
- procedure SetDepthOfView(aValue: Single);
- procedure SetFocalLength(aValue: Single);
- procedure SetCameraStyle(const val: TgxCameraStyle);
- procedure SetKeepFOVMode(const val: TgxCameraKeepFOVMode);
- procedure SetSceneScale(Value: Single);
- function StoreSceneScale: Boolean;
- procedure SetNearPlaneBias(Value: Single);
- function StoreNearPlaneBias: Boolean;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- (* Nearest clipping plane for the frustum.
- This value depends on the FocalLength and DepthOfView fields and
- is calculated to minimize Z-Buffer crawling as suggested by the OpenGL documentation. *)
- property NearPlane: Single read FNearPlane;
- // Apply camera transformation
- procedure Apply;
- procedure DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean); override;
- function RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil)
- : Boolean; override;
- procedure ApplyPerspective(const AViewport: TRectangle; AWidth, AHeight: Integer; ADPI: Integer);
- procedure AutoLeveling(Factor: Single);
- procedure Reset(aSceneBuffer: TgxSceneBuffer);
- // Position the camera so that the whole scene can be seen
- procedure ZoomAll(aSceneBuffer: TgxSceneBuffer);
- procedure RotateObject(obj: TgxBaseSceneObject; pitchDelta, turnDelta: Single; rollDelta: Single = 0);
- procedure RotateTarget(pitchDelta, turnDelta: Single; rollDelta: Single = 0);
- (* Change camera's position to make it move around its target.
- If TargetObject is nil, nothing happens. This method helps in quickly
- implementing camera controls. Camera's Up and Direction properties are unchanged.
- Angle deltas are in degrees, camera parent's coordinates should be identity.
- Tip : make the camera a child of a "target" dummycube and make
- it a target the dummycube. Now, to pan across the scene, just move
- the dummycube, to change viewing angle, use this method. *)
- procedure MoveAroundTarget(pitchDelta, turnDelta: Single);
- (* Change camera's position to make it move all around its target.
- If TargetObject is nil, nothing happens. This method helps in quickly
- implementing camera controls. Camera's Up and Direction properties are changed.
- Angle deltas are in degrees. *)
- procedure MoveAllAroundTarget(pitchDelta, turnDelta: Single);
- // Moves the camera in eye space coordinates.
- procedure MoveInEyeSpace(forwardDistance, rightDistance, upDistance: Single);
- // Moves the target in eye space coordinates.
- procedure MoveTargetInEyeSpace(forwardDistance, rightDistance, upDistance: Single);
- // Computes the absolute vector corresponding to the eye-space translations.
- function AbsoluteEyeSpaceVector(forwardDistance, rightDistance, upDistance: Single): TVector4f;
- (* Adjusts distance from camera to target by applying a ratio.
- If TargetObject is nil, nothing happens. This method helps in quickly
- implementing camera controls. Only the camera's position is changed. *)
- procedure AdjustDistanceToTarget(distanceRatio: Single);
- (* Returns the distance from camera to target.
- If TargetObject is nil, returns 1. *)
- function DistanceToTarget: Single;
- (* Computes the absolute normalized vector to the camera target.
- If no target is defined, AbsoluteDirection is returned. *)
- function AbsoluteVectorToTarget: TVector4f;
- (* Computes the absolute normalized right vector to the camera target.
- If no target is defined, AbsoluteRight is returned. *)
- function AbsoluteRightVectorToTarget: TVector4f;
- (* Computes the absolute normalized up vector to the camera target.
- If no target is defined, AbsoluteUpt is returned. *)
- function AbsoluteUpVectorToTarget: TVector4f;
- (* Calculate an absolute translation vector from a screen vector.
- Ratio is applied to both screen delta, planeNormal should be the
- translation plane's normal. *)
- function ScreenDeltaToVector(deltaX, deltaY: Integer; ratio: Single; const planeNormal: TVector4f): TVector4f;
- // Same as ScreenDeltaToVector but optimized for XY plane.
- function ScreenDeltaToVectorXY(deltaX, deltaY: Integer; ratio: Single): TVector4f;
- // Same as ScreenDeltaToVector but optimized for XZ plane.
- function ScreenDeltaToVectorXZ(deltaX, deltaY: Integer; ratio: Single): TVector4f;
- // Same as ScreenDeltaToVector but optimized for YZ plane.
- function ScreenDeltaToVectorYZ(deltaX, deltaY: Integer; ratio: Single): TVector4f;
- // Returns true if a point is in front of the camera.
- function PointInFront(const point: TVector4f): Boolean; overload;
- (* Calculates the field of view in degrees, given a viewport dimension
- (width or height). F.i. you may wish to use the minimum of the two. *)
- function GetFieldOfView(const AViewportDimension: Single): Single;
- (* Sets the FocalLength in degrees, given a field of view and a viewport
- dimension (width or height). *)
- procedure SetFieldOfView(const AFieldOfView, AViewportDimension: Single);
- published
- (* Depth of field/view.
- Adjusts the maximum distance, beyond which objects will be clipped
- (ie. not visisble).
- You must adjust this value if you are experiencing disappearing
- objects (increase the value) of Z-Buffer crawling (decrease the
- value). Z-Buffer crawling happens when depth of view is too large
- and the Z-Buffer precision cannot account for all that depth
- accurately : objects farther overlap closer objects and vice-versa.
- Note that this value is ignored in cSOrtho2D mode. *)
- property DepthOfView: Single read FDepthOfView write SetDepthOfView;
- (* Focal Length of the camera.
- Adjusting this value allows for lens zooming effects (use SceneScale
- for linear zooming). This property affects near/far planes clipping. *)
- property FocalLength: Single read FFocalLength write SetFocalLength;
- (* Scene scaling for camera point.
- This is a linear 2D scaling of the camera's output, allows for
- linear zooming (use FocalLength for lens zooming). *)
- property SceneScale: Single read FSceneScale write SetSceneScale stored StoreSceneScale;
- (* Scaling bias applied to near-plane calculation.
- Values inferior to one will move the nearplane nearer, and also
- reduce medium/long range Z-Buffer precision, values superior
- to one will move the nearplane farther, and also improve medium/long
- range Z-Buffer precision. *)
- property NearPlaneBias: Single read FNearPlaneBias write SetNearPlaneBias stored StoreNearPlaneBias;
- (* If set, camera will point to this object.
- When camera is pointing an object, the Direction vector is ignored
- and the Up vector is used as an absolute vector to the up. *)
- property TargetObject: TgxBaseSceneObject read FTargetObject write SetTargetObject;
- (* Adjust the camera style.
- Three styles are available :
- csPerspective, the default value for perspective projection
- csOrthogonal, for orthogonal (or isometric) projection.
- csOrtho2D, setups orthogonal 2D projection in which 1 unit
- (in x or y) represents 1 pixel.
- csInfinitePerspective, for perspective view without depth limit.
- csKeepCamAnglePerspective, for perspective view with keeping aspect on view resize.
- csCustom, setup is deferred to the OnCustomPerspective event. *)
- property CameraStyle: TgxCameraStyle read FCameraStyle write SetCameraStyle default csPerspective;
- (* Keep camera angle mode.
- When CameraStyle is csKeepCamAnglePerspective, select which camera angle you want to keep.
- kaHeight, for Keep Height oriented camera angle
- kaWidth, for Keep Width oriented camera angle *)
- property KeepFOVMode: TgxCameraKeepFOVMode read FKeepFOVMode write SetKeepFOVMode default ckmHorizontalFOV;
- (* Custom perspective event.
- This event allows you to specify your custom perpective, either
- with a glFrustrum, a glOrtho or whatever method suits you.
- You must compute viewPortRadius for culling to work.
- This event is only called if CameraStyle is csCustom. *)
- property OnCustomPerspective: TOnCustomPerspective read FOnCustomPerspective write FOnCustomPerspective;
- property Position;
- property Direction;
- property Up;
- property OnProgress;
- end;
- (* Scene object.
- The scene contains the scene description (lights, geometry...), which is
- basicly a hierarchical scene graph made of TgxBaseSceneObject. It will
- usually contain one or more TgxCamera object, which can be referred by
- a Viewer component for rendering purposes.
- The scene's objects can be accessed directly from Delphi code (as regular
- components), but those are edited with a specific editor (double-click
- on the TgxScene component at design-time to invoke it). To add objects
- at runtime, use the AddNewChild method of TgxBaseSceneObject. *)
- TgxScene = class(TgxUpdateAbleComponent)
- private
- FUpdateCount: Integer;
- FObjects: TgxSceneRootObject;
- FBaseContext: TgxContext; // reference, not owned!
- FLights, FBuffers: TgxPersistentObjectList;
- FCurrentCamera: TgxCamera;
- FCurrentBuffer: TgxSceneBuffer;
- FObjectsSorting: TgxObjectsSorting;
- FVisibilityCulling: TgxVisibilityCulling;
- FOnBeforeProgress: TgxProgressEvent;
- FOnProgress: TgxProgressEvent;
- FCurrentDeltaTime: Double;
- FInitializableObjects: TgxInitializableObjectList;
- protected
- procedure AddLight(aLight: TgxLightSource);
- procedure RemoveLight(aLight: TgxLightSource);
- // Adds all lights in the subtree (anObj included)
- procedure AddLights(anObj: TgxBaseSceneObject);
- // Removes all lights in the subtree (anObj included)
- procedure RemoveLights(anObj: TgxBaseSceneObject);
- procedure GetChildren(AProc: TGetChildProc; Root: TComponent); override;
- procedure SetChildOrder(AChild: TComponent; Order: Integer); override;
- procedure SetObjectsSorting(const val: TgxObjectsSorting);
- procedure SetVisibilityCulling(const val: TgxVisibilityCulling);
- procedure ReadState(reader: TReader); override;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure BeginUpdate;
- procedure EndUpdate;
- function IsUpdating: Boolean;
- procedure AddBuffer(aBuffer: TgxSceneBuffer);
- procedure RemoveBuffer(aBuffer: TgxSceneBuffer);
- procedure SetupLights(maxLights: Integer);
- procedure NotifyChange(Sender: TObject); override;
- procedure Progress(const deltaTime, newTime: Double);
- function FindSceneObject(const aName: string): TgxBaseSceneObject;
- (* Calculates, finds and returns the first object intercepted by the ray.
- Returns nil if no intersection was found. This function will be
- accurate only for objects that overrided their RayCastIntersect
- method with accurate code, otherwise, bounding sphere intersections
- will be returned. *)
- function RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil)
- : TgxBaseSceneObject; virtual;
- procedure ShutdownAllLights;
- // Saves the scene to a file (recommended extension : .GLS)
- procedure SaveToFile(const fileName: string);
- (* Load the scene from a file.
- Existing objects/lights/cameras are freed, then the file is loaded.
- Delphi's IDE is not handling this behaviour properly yet, ie. if
- you load a scene in the IDE, objects will be properly loaded, but
- no declare will be placed in the code. *)
- procedure LoadFromFile(const fileName: string);
- procedure SaveToStream(aStream: TStream);
- procedure LoadFromStream(aStream: TStream);
- // Saves the scene to a text file
- procedure SaveToTextFile(const fileName: string);
- (* Load the scene from a text files.
- See LoadFromFile for details. *)
- procedure LoadFromTextFile(const fileName: string);
- property CurrentCamera: TgxCamera read FCurrentCamera;
- property Lights: TgxPersistentObjectList read FLights;
- property Objects: TgxSceneRootObject read FObjects;
- property CurrentBuffer: TgxSceneBuffer read FCurrentBuffer;
- (* List of objects that request to be initialized when rendering context is active.
- They are removed automaticly from this list once initialized. *)
- property InitializableObjects: TgxInitializableObjectList read FInitializableObjects;
- property CurrentDeltaTime: Double read FCurrentDeltaTime;
- published
- // Defines default ObjectSorting option for scene objects.
- property ObjectsSorting: TgxObjectsSorting read FObjectsSorting write SetObjectsSorting default osRenderBlendedLast;
- // Defines default VisibilityCulling option for scene objects.
- property VisibilityCulling: TgxVisibilityCulling read FVisibilityCulling write SetVisibilityCulling default vcNone;
- property OnBeforeProgress: TgxProgressEvent read FOnBeforeProgress write FOnBeforeProgress;
- property OnProgress: TgxProgressEvent read FOnProgress write FOnProgress;
- end;
- TgxFogMode = (fmLinear, fmExp, fmExp2);
- (* Fog distance calculation mode.
- fdDefault: let OpenGL use its default formula
- fdEyeRadial: uses radial "true" distance (best quality)
- fdEyePlane: uses the distance to the projection plane (same as Z-Buffer, faster)
- Requires support of GL_NV_fog_distance extension, otherwise, it is ignored. *)
- TgxFogDistance = (fdDefault, fdEyeRadial, fdEyePlane);
- (* Parameters for fog environment in a scene.
- The fog descibed by this object is a distance-based fog, ie. the "intensity"
- of the fog is given by a formula depending solely on the distance, this
- intensity is used for blending to a fixed color. *)
- TgxFogEnvironment = class(TgxUpdateAbleObject)
- private
- FSceneBuffer: TgxSceneBuffer;
- FFogColor: TgxColor; // alpha value means the fog density
- FFogStart, FFogEnd: Single;
- FFogMode: TgxFogMode;
- FFogDistance: TgxFogDistance;
- protected
- procedure SetFogColor(Value: TgxColor);
- procedure SetFogStart(Value: Single);
- procedure SetFogEnd(Value: Single);
- procedure SetFogMode(Value: TgxFogMode);
- procedure SetFogDistance(const val: TgxFogDistance);
- public
- constructor Create(AOwner: TPersistent); override;
- destructor Destroy; override;
- procedure ApplyFog;
- procedure Assign(Source: TPersistent); override;
- function IsAtDefaultValues: Boolean;
- published
- // Color of the fog when it is at 100% intensity.
- property FogColor: TgxColor read FFogColor write SetFogColor;
- // Minimum distance for fog, what is closer is not affected.
- property FogStart: Single read FFogStart write SetFogStart;
- // Maximum distance for fog, what is farther is at 100% fog intensity.
- property FogEnd: Single read FFogEnd write SetFogEnd;
- // The formula used for converting distance to fog intensity.
- property FogMode: TgxFogMode read FFogMode write SetFogMode default fmLinear;
- (* Adjusts the formula used for calculating fog distances.
- This option is honoured if and only if the OpenGL ICD supports the
- GL_NV_fog_distance extension, otherwise, it is ignored.
- fdDefault: let OpenGL use its default formula
- fdEyeRadial: uses radial "true" distance (best quality)
- fdEyePlane: uses the distance to the projection plane (same as Z-Buffer, faster) *)
- property FogDistance: TgxFogDistance read FFogDistance write SetFogDistance default fdDefault;
- end;
- TgxDepthPrecision = (dpDefault, dp16bits, dp24bits, dp32bits);
- TgxColorDepth = (cdDefault, cd8bits, cd16bits, cd24bits, cdFloat64bits, cdFloat128bits); // float_type
- TgxShadeModel = (smDefault, smSmooth, smFlat);
- // Encapsulates an OpenGL frame/rendering buffer.
- TgxSceneBuffer = class(TgxUpdateAbleObject)
- private
- // Internal state
- FRendering: Boolean;
- FRenderingContext: TgxContext;
- FAfterRenderEffects: TgxPersistentObjectList;
- FViewMatrixStack: array of TMatrix4f;
- FProjectionMatrixStack: array of TMatrix4f;
- FBaseProjectionMatrix: TMatrix4f;
- FCameraAbsolutePosition: TVector4f;
- FViewPort: TRectangle;
- FSelector: TgxBaseSelectTechnique;
- // Options & User Properties
- FFaceCulling, FFogEnable, FLighting: Boolean;
- FDepthTest: Boolean;
- FBackgroundColor: TColor;
- FBackgroundAlpha: Single;
- FAmbientColor: TgxColor;
- FAntiAliasing: TgxAntiAliasing;
- FDepthPrecision: TgxDepthPrecision;
- FColorDepth: TgxColorDepth;
- FContextOptions: TContextOptions;
- FShadeModel: TgxShadeModel;
- FRenderDPI: Integer;
- FFogEnvironment: TgxFogEnvironment;
- FAccumBufferBits: Integer;
- FLayer: TgxContextLayer;
- // Cameras
- FCamera: TgxCamera;
- // Freezing
- FFreezeBuffer: Pointer;
- FFreezed: Boolean;
- FFreezedViewPort: TRectangle;
- // Monitoring
- FFrameCount: Longint;
- FFramesPerSecond: Single;
- FFirstPerfCounter: Int64;
- FLastFrameTime: Single;
- // Events
- FOnChange: TNotifyEvent;
- FOnStructuralChange: TNotifyEvent;
- FOnPrepareGLContext: TNotifyEvent;
- FBeforeRender: TNotifyEvent;
- FViewerBeforeRender: TNotifyEvent;
- FPostRender: TNotifyEvent;
- FAfterRender: TNotifyEvent;
- FInitiateRendering: TDirectRenderEvent;
- FWrapUpRendering: TDirectRenderEvent;
- procedure SetLayer(const Value: TgxContextLayer);
- protected
- procedure SetBackgroundColor(AColor: TColor);
- procedure SetBackgroundAlpha(alpha: Single);
- procedure SetAmbientColor(AColor: TgxColor);
- function GetLimit(Which: TLimitType): Integer;
- procedure SetCamera(ACamera: TgxCamera);
- procedure SetContextOptions(Options: TContextOptions);
- procedure SetDepthTest(aValue: Boolean);
- procedure SetFaceCulling(aValue: Boolean);
- procedure SetLighting(aValue: Boolean);
- procedure SetAntiAliasing(const val: TgxAntiAliasing);
- procedure SetDepthPrecision(const val: TgxDepthPrecision);
- procedure SetColorDepth(const val: TgxColorDepth);
- procedure SetShadeModel(const val: TgxShadeModel);
- procedure SetFogEnable(aValue: Boolean);
- procedure SetFogEnvironment(aValue: TgxFogEnvironment);
- function StoreFog: Boolean;
- procedure SetAccumBufferBits(const val: Integer);
- procedure PrepareRenderingMatrices(const AViewport: TRectangle; resolution: Integer; pickingRect: PRect = nil);
- procedure DoBaseRender(const AViewport: TRectangle; resolution: Integer; drawState: TgxDrawState;
- baseObject: TgxBaseSceneObject);
- procedure SetupRenderingContext(Context: TgxContext);
- procedure SetupRCOptions(Context: TgxContext);
- procedure PrepareGLContext;
- procedure DoChange;
- procedure DoStructuralChange;
- // DPI for current/last render
- property RenderDPI: Integer read FRenderDPI;
- property OnPrepareGLContext: TNotifyEvent read FOnPrepareGLContext write FOnPrepareGLContext;
- public
- constructor Create(AOwner: TPersistent); override;
- destructor Destroy; override;
- procedure NotifyChange(Sender: TObject); override;
- procedure CreateRC(AWindowHandle: THandle; memoryContext: Boolean; // in VCL -> HWND
- BufferCount: Integer = 1); overload;
- procedure ClearBuffers;
- procedure DestroyRC;
- function RCInstantiated: Boolean;
- procedure Resize(newLeft, newTop, newWidth, newHeight: Integer);
- // Indicates hardware acceleration support
- function Acceleration: TgxContextAcceleration;
- // ViewPort for current/last render
- property viewport: TRectangle read FViewPort;
- // Fills the PickList with objects in Rect area
- procedure PickObjects(const rect: TRect; pickList: TgxPickList; objectCountGuess: Integer);
- (* Returns a PickList with objects in Rect area.
- Returned list should be freed by caller.
- Objects are sorted by depth (nearest objects first). *)
- function GetPickedObjects(const rect: TRect; objectCountGuess: Integer = 64): TgxPickList;
- // Returns the nearest object at x, y coordinates or nil if there is none
- function GetPickedObject(x, y: Integer): TgxBaseSceneObject;
- // Returns the color of the pixel at x, y in the frame buffer
- function GetPixelColor(x, y: Integer): TColor;
- (* Returns the raw depth (Z buffer) of the pixel at x, y in the frame buffer.
- This value does not map to the actual eye-object distance, but to
- a depth buffer value in the [0; 1] range. *)
- function GetPixelDepth(x, y: Integer): Single;
- (* Converts a raw depth (Z buffer value) to frustrum distance.
- This calculation is only accurate for the pixel at the centre of the viewer,
- because it does not take into account that the corners of the frustrum
- are further from the eye than its centre. *)
- function PixelDepthToDistance(aDepth: Single): Single;
- (* Converts a raw depth (Z buffer value) to world distance.
- It also compensates for the fact that the corners of the frustrum
- are further from the eye, than its centre. *)
- function PixelToDistance(x, y: Integer): Single;
- // Design time notification
- procedure NotifyMouseMove(Shift: TShiftState; x, y: Single);
- (* Renders the scene on the viewer.
- You do not need to call this method, unless you explicitly want a
- render at a specific time. If you just want the control to get
- refreshed, use Invalidate instead. *)
- procedure Render(baseObject: TgxBaseSceneObject); overload;
- procedure Render; overload;
- procedure RenderScene(aScene: TgxScene; const viewPortSizeX, viewPortSizeY: Integer; drawState: TgxDrawState;
- baseObject: TgxBaseSceneObject);
- (* Render the scene to a bitmap at given DPI.
- DPI = "dots per inch".
- The "magic" DPI of the screen is 96 under Windows. *)
- procedure RenderToBitmap(ABitmap: TBitmap; DPI: Integer = 0);
- (* Render the scene to a bitmap at given DPI and saves it to a file.
- DPI = "dots per inch".
- The "magic" DPI of the screen is 96 under Windows. *)
- procedure RenderToFile(const AFile: string; DPI: Integer = 0); overload;
- (* Renders to bitmap of given size, then saves it to a file.
- DPI is adjusted to make the bitmap similar to the viewer. *)
- procedure RenderToFile(const AFile: string; bmpWidth, bmpHeight: Integer); overload;
- (* Creates a TgxBitmap32 that is a snapshot of current OpenGL content.
- When possible, use this function instead of RenderToBitmap, it won't
- request a redraw and will be significantly faster.
- The returned TgxBitmap32 should be freed by calling code. *)
- function CreateSnapShot: TgxImage;
- // Creates a bitmap that is a snapshot of current graphic content.
- function CreateSnapShotBitmap: TBitmap;
- procedure CopyToTexture(aTexture: TgxTexture); overload;
- procedure CopyToTexture(aTexture: TgxTexture; xSrc, ySrc, AWidth, AHeight: Integer; xDest, yDest: Integer;
- glCubeFace: GLEnum = 0); overload;
- // Save as raw float data to a file
- procedure SaveAsFloatToFile(const aFilename: string);
- // Event reserved for viewer-specific uses.
- property ViewerBeforeRender: TNotifyEvent read FViewerBeforeRender write FViewerBeforeRender stored False;
- procedure SetViewPort(x, y, W, H: Integer);
- function width: Integer;
- function height: Integer;
- // Indicates if the Viewer is "frozen".
- property Freezed: Boolean read FFreezed;
- (* Freezes rendering leaving the last rendered scene on the buffer. This
- is usefull in windowed applications for temporarily stopping rendering
- (when moving the window, for example). *)
- procedure Freeze;
- { Restarts rendering after it was freezed. }
- procedure Melt;
- // Displays a window with info on current OpenGL ICD and context.
- procedure ShowInfo(Modal: Boolean = False);
- // Currently Rendering?
- property Rendering: Boolean read FRendering;
- // Adjusts background alpha channel.
- property BackgroundAlpha: Single read FBackgroundAlpha write SetBackgroundAlpha;
- // Returns the projection matrix in use or used for the last rendering.
- function ProjectionMatrix: TMatrix4f; deprecated;
- // Returns the view matrix in use or used for the last rendering.
- function ViewMatrix: TMatrix4f; deprecated;
- function ModelMatrix: TMatrix4f; deprecated;
- (* Returns the base projection matrix in use or used for the last rendering.
- The "base" projection is (as of now) either identity or the pick
- matrix, ie. it is the matrix on which the perspective or orthogonal
- matrix gets applied. *)
- property BaseProjectionMatrix: TMatrix4f read FBaseProjectionMatrix;
- (* Back up current View matrix and replace it with newMatrix.
- This method has no effect on theOpenVX matrix, only on the Buffer's
- matrix, and is intended for special effects rendering. *)
- procedure PushViewMatrix(const newMatrix: TMatrix4f); deprecated;
- // Restore a View matrix previously pushed.
- procedure PopViewMatrix; deprecated;
- procedure PushProjectionMatrix(const newMatrix: TMatrix4f); deprecated;
- procedure PopProjectionMatrix; deprecated;
- (* Converts a screen pixel coordinate into 3D coordinates for orthogonal projection.
- This function accepts standard canvas coordinates, with (0,0) being
- the top left corner, and returns, when the camera is in orthogonal
- mode, the corresponding 3D world point that is in the camera's plane. *)
- function OrthoScreenToWorld(screenX, screenY: Integer): TAffineVector; overload;
- (* Converts a screen coordinate into world (3D) coordinates.
- This methods wraps a call to gluUnProject.
- Note that screen coord (0,0) is the lower left corner. *)
- function ScreenToWorld(const aPoint: TAffineVector): TAffineVector; overload;
- function ScreenToWorld(const aPoint: TVector4f): TVector4f; overload;
- (* Converts a screen pixel coordinate into 3D world coordinates.
- This function accepts standard canvas coordinates, with (0,0) being
- the top left corner. *)
- function ScreenToWorld(screenX, screenY: Integer): TAffineVector; overload;
- (* Converts an absolute world coordinate into screen coordinate.
- This methods wraps a call to gluProject.
- Note that screen coord (0,0) is the lower left corner. *)
- function WorldToScreen(const aPoint: TAffineVector): TAffineVector; overload;
- function WorldToScreen(const aPoint: TVector4f): TVector4f; overload;
- // Converts a set of point absolute world coordinates into screen coordinates.
- procedure WorldToScreen(points: PVector4f; nbPoints: Integer); overload;
- (* Calculates the 3D vector corresponding to a 2D screen coordinate.
- The vector originates from the camera's absolute position and is
- expressed in absolute coordinates.
- Note that screen coord (0,0) is the lower left corner. *)
- function ScreenToVector(const aPoint: TAffineVector): TAffineVector; overload;
- function ScreenToVector(const aPoint: TVector4f): TVector4f; overload;
- function ScreenToVector(const x, y: Integer): TVector4f; overload;
- (* Calculates the 2D screen coordinate of a vector from the camera's
- absolute position and is expressed in absolute coordinates.
- Note that screen coord (0,0) is the lower left corner. *)
- function VectorToScreen(const VectToCam: TAffineVector): TAffineVector;
- (* Calculates intersection between a plane and screen vector.
- If an intersection is found, returns True and places result in
- intersectPoint. *)
- function ScreenVectorIntersectWithPlane(const aScreenPoint: TVector4f; const planePoint, planeNormal: TVector4f;
- var intersectPoint: TVector4f): Boolean;
- (* Calculates intersection between plane XY and screen vector.
- If an intersection is found, returns True and places result in intersectPoint. *)
- function ScreenVectorIntersectWithPlaneXY(const aScreenPoint: TVector4f; const z: Single;
- var intersectPoint: TVector4f): Boolean;
- (* Calculates intersection between plane YZ and screen vector.
- If an intersection is found, returns True and places result in intersectPoint. *)
- function ScreenVectorIntersectWithPlaneYZ(const aScreenPoint: TVector4f; const x: Single;
- var intersectPoint: TVector4f): Boolean;
- (* Calculates intersection between plane XZ and screen vector.
- If an intersection is found, returns True and places result in intersectPoint. *)
- function ScreenVectorIntersectWithPlaneXZ(const aScreenPoint: TVector4f; const y: Single;
- var intersectPoint: TVector4f): Boolean;
- (* Calculates a 3D coordinate from screen position and ZBuffer.
- This function returns a world absolute coordinate from a 2D point
- in the viewer, the depth being extracted from the ZBuffer data
- (DepthTesting and ZBuffer must be enabled for this function to work).
- Note that ZBuffer precision is not linear and can be quite low on
- some boards (either from compression or resolution approximations). *)
- function PixelRayToWorld(x, y: Integer): TAffineVector;
- (* Time (in second) spent to issue rendering order for the last frame.
- Be aware that since execution by the hardware isn't synchronous,
- this value may not be an accurate measurement of the time it took
- to render the last frame, it's a measurement of only the time it
- took to issue rendering orders. *)
- property LastFrameTime: Single read FLastFrameTime;
- (* Current FramesPerSecond rendering speed.
- You must keep the renderer busy to get accurate figures from this
- property.
- This is an average value, to reset the counter, call
- ResetPerfomanceMonitor. *)
- property FramesPerSecond: Single read FFramesPerSecond;
- (* Resets the perfomance monitor and begin a new statistics set.
- See FramesPerSecond. *)
- procedure ResetPerformanceMonitor;
- (* Retrieve one of the OpenGL limits for the current viewer.
- Limits include max texture size, OpenGL stack depth, etc. *)
- property LimitOf[Which: TLimitType]: Integer read GetLimit;
- (* Current rendering context.
- The context is a wrapper around platform-specific contexts
- (see TgxContext) and takes care of context activation and handle
- management. *)
- property RenderingContext: TgxContext read FRenderingContext;
- (* The camera from which the scene is rendered.
- A camera is an object you can add and define in a TgxScene component. *)
- property Camera: TgxCamera read FCamera write SetCamera;
- // Specifies the layer plane that the rendering context is bound to.
- property Layer: TgxContextLayer read FLayer write SetLayer default clMainPlane;
- published
- // Fog environment options. See TgxFogEnvironment.
- property FogEnvironment: TgxFogEnvironment read FFogEnvironment write SetFogEnvironment stored StoreFog;
- // Color used for filling the background prior to any rendering.
- property BackgroundColor: TColor read FBackgroundColor write SetBackgroundColor default TColors.SysBtnFace;
- (* Scene ambient color vector.
- This ambient color is defined independantly from all lightsources,
- which can have their own ambient components. *)
- property AmbientColor: TgxColor read FAmbientColor write SetAmbientColor;
- (* Context options allows to setup specifics of the rendering context.
- Not all contexts support all options. *)
- property ContextOptions: TContextOptions read FContextOptions write SetContextOptions
- default [roDoubleBuffer, roRenderToWindow, roDebugContext];
- // Number of precision bits for the accumulation buffer.
- property AccumBufferBits: Integer read FAccumBufferBits write SetAccumBufferBits default 0;
- (* DepthTest enabling.
- When DepthTest is enabled, objects closer to the camera will hide
- farther ones (via use of Z-Buffering).
- When DepthTest is disabled, the latest objects drawn/rendered overlap
- all previous objects, whatever their distance to the camera.
- Even when DepthTest is enabled, objects may chose to ignore depth
- testing through the osIgnoreDepthBuffer of their ObjectStyle property. *)
- property DepthTest: Boolean read FDepthTest write SetDepthTest default True;
- (* Enable or disable face culling in the renderer.
- Face culling is used in hidden faces removal algorithms : each face
- is given a normal or 'outside' direction. When face culling is enabled,
- only faces whose normal points towards the observer are rendered. *)
- property FaceCulling: Boolean read FFaceCulling write SetFaceCulling default True;
- // Toggle to enable or disable the fog settings.
- property FogEnable: Boolean read FFogEnable write SetFogEnable default False;
- (* Toggle to enable or disable lighting calculations.
- When lighting is enabled, objects will be lit according to lightsources,
- when lighting is disabled, objects are rendered in their own colors,
- without any shading.
- Lighting does NOT generate shadows in OpenGL. *)
- property Lighting: Boolean read FLighting write SetLighting default True;
- (* AntiAliasing option.
- Ignored if not hardware supported, currently based on ARB_multisample. *)
- property AntiAliasing: TgxAntiAliasing read FAntiAliasing write SetAntiAliasing default aaDefault;
- (* Depth buffer precision.
- Default is highest available (below and including 24 bits) *)
- property DepthPrecision: TgxDepthPrecision read FDepthPrecision write SetDepthPrecision default dpDefault;
- (* Color buffer depth.
- Default depth buffer is highest available (below and including 24 bits) *)
- property ColorDepth: TgxColorDepth read FColorDepth write SetColorDepth default cdDefault;
- // Shade model. Default is "Smooth".
- property ShadeModel: TgxShadeModel read FShadeModel write SetShadeModel default smDefault;
- (* Indicates a change in the scene or buffer options.
- A simple re-render is enough to take into account the changes. *)
- property OnChange: TNotifyEvent read FOnChange write FOnChange stored False;
- (* Indicates a structural change in the scene or buffer options.
- A reconstruction of the RC is necessary to take into account the
- changes (this may lead to a driver switch or lengthy operations). *)
- property OnStructuralChange: TNotifyEvent read FOnStructuralChange write FOnStructuralChange stored False;
- (* Triggered before the scene's objects get rendered.
- You may use this event to execute your own OpenGL rendering
- (usually background stuff). *)
- property BeforeRender: TNotifyEvent read FBeforeRender write FBeforeRender stored False;
- (* Triggered after BeforeRender, before rendering objects.
- This one is fired after the rci has been initialized and can be used
- to alter it or perform early renderings that require an rci,
- the Sender is the buffer. *)
- property InitiateRendering: TDirectRenderEvent read FInitiateRendering write FInitiateRendering stored False;
- (* Triggered after rendering all scene objects, before PostRender.
- This is the last point after which the rci becomes unavailable,
- the Sender is the buffer. *)
- property WrapUpRendering: TDirectRenderEvent read FWrapUpRendering write FWrapUpRendering stored False;
- (* Triggered just after all the scene's objects have been rendered.
- The OpenGL context is still active in this event, and you may use it
- to execute your own OpenGL rendering (usually for HUD, 2D overlays
- or after effects). *)
- property PostRender: TNotifyEvent read FPostRender write FPostRender stored False;
- (* Called after rendering.
- You cannot issue OpenGL calls in this event, if you want to do your own
- OpenGL stuff, use the PostRender event. *)
- property AfterRender: TNotifyEvent read FAfterRender write FAfterRender stored False;
- end;
- (* Base class for non-visual viewer.
- Non-visual viewer may actually render visuals, but they are non-visual
- (ie. non interactive) at design time. Such viewers include memory
- or full-screen viewers. *)
- TgxNonVisualViewer = class(TComponent)
- private
- FBuffer: TgxSceneBuffer;
- FWidth, FHeight: Integer;
- FCubeMapRotIdx: Integer;
- FCubeMapZNear, FCubeMapZFar: Single;
- FCubeMapTranslation: TAffineVector;
- // FCreateTexture : Boolean;
- protected
- procedure SetBeforeRender(const val: TNotifyEvent);
- function GetBeforeRender: TNotifyEvent;
- procedure SetPostRender(const val: TNotifyEvent);
- function GetPostRender: TNotifyEvent;
- procedure SetAfterRender(const val: TNotifyEvent);
- function GetAfterRender: TNotifyEvent;
- procedure SetCamera(const val: TgxCamera);
- function GetCamera: TgxCamera;
- procedure SetBuffer(const val: TgxSceneBuffer);
- procedure SetWidth(const val: Integer);
- procedure SetHeight(const val: Integer);
- procedure SetupCubeMapCamera(Sender: TObject);
- procedure DoOnPrepareVXContext(Sender: TObject);
- procedure PrepareVXContext; virtual;
- procedure DoBufferChange(Sender: TObject); virtual;
- procedure DoBufferStructuralChange(Sender: TObject); virtual;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure Render(baseObject: TgxBaseSceneObject = nil); virtual; abstract;
- procedure CopyToTexture(aTexture: TgxTexture); overload; virtual;
- procedure CopyToTexture(aTexture: TgxTexture; xSrc, ySrc, width, height: Integer; xDest, yDest: Integer); overload;
- // CopyToTexture for Multiple-Render-Target
- procedure CopyToTextureMRT(aTexture: TgxTexture; BufferIndex: Integer); overload; virtual;
- procedure CopyToTextureMRT(aTexture: TgxTexture; xSrc, ySrc, width, height: Integer; xDest, yDest: Integer;
- BufferIndex: Integer); overload;
- (* Renders the 6 texture maps from a scene.
- The viewer is used to render the 6 images, one for each face
- of the cube, from the absolute position of the camera.
- This does NOT alter the content of the Pictures in the image,
- and will only change or define the content of textures as
- registered by OpenGL. *)
- procedure RenderCubeMapTextures(cubeMapTexture: TgxTexture; zNear: Single = 0; zFar: Single = 0);
- published
- // Camera from which the scene is rendered.
- property Camera: TgxCamera read GetCamera write SetCamera;
- property width: Integer read FWidth write SetWidth default 256;
- property height: Integer read FHeight write SetHeight default 256;
- (* Triggered before the scene's objects get rendered.
- You may use this event to execute your own OpenGL rendering. *)
- property BeforeRender: TNotifyEvent read GetBeforeRender write SetBeforeRender;
- (* Triggered just after all the scene's objects have been rendered.
- The OpenGL context is still active in this event, and you may use it
- to execute your own OpenGL rendering. *)
- property PostRender: TNotifyEvent read GetPostRender write SetPostRender;
- (* Called after rendering.
- You cannot issue OpenGL calls in this event, if you want to do your own
- OpenGL stuff, use the PostRender event. *)
- property AfterRender: TNotifyEvent read GetAfterRender write SetAfterRender;
- // Access to buffer properties.
- property Buffer: TgxSceneBuffer read FBuffer write SetBuffer;
- end;
- (* Component to render a scene to memory only.
- This component curently requires that the OpenGL ICD supports the
- WGL_ARB_pbuffer extension (indirectly). *)
- TgxMemoryViewer = class(TgxNonVisualViewer)
- private
- FBufferCount: Integer;
- procedure SetBufferCount(const Value: Integer);
- public
- constructor Create(AOwner: TComponent); override;
- procedure InstantiateRenderingContext;
- procedure Render(baseObject: TgxBaseSceneObject = nil); override;
- published
- (* Set BufferCount > 1 for multiple render targets.
- Users should check if the corresponding extension (GL_ATI_draw_buffers)
- is supported. Current hardware limit is BufferCount = 4. *)
- property BufferCount: Integer read FBufferCount write SetBufferCount default 1;
- end;
- TInvokeInfoForm = procedure(aSceneBuffer: TgxSceneBuffer; Modal: Boolean);
- (* Register an event handler triggered by any TgxBaseSceneObject Name change.
- *INCOMPLETE*, currently allows for only 1 (one) event, and is used by
- FSceneEdit in the IDE. *)
- procedure RegisterBaseSceneObjectNameChangeEvent(notifyEvent: TNotifyEvent);
- (* Deregister an event handler triggered by any TgxBaseSceneObject Name change.
- See RegisterVKBaseSceneObjectNameChangeEvent. *)
- procedure DeRegisterBaseSceneObjectNameChangeEvent(notifyEvent: TNotifyEvent);
- (* Register an event handler triggered by any TgxBehaviour Name change.
- *INCOMPLETE*, currently allows for only 1 (one) event, and is used by
- FBehavioursEditor in the IDE. *)
- procedure RegisterBehaviourNameChangeEvent(notifyEvent: TNotifyEvent);
- (* Deregister an event handler triggered by any TgxBaseSceneObject Name change.
- See RegisterVKBaseSceneObjectNameChangeEvent. *)
- procedure DeRegisterBehaviourNameChangeEvent(notifyEvent: TNotifyEvent);
- // Issues OpenGL calls for drawing X, Y, Z axes in a standard style.
- procedure AxesBuildList(var rci: TgxRenderContextInfo; pattern: Word; AxisLen: Single);
- // Registers the procedure call used to invoke the info form.
- procedure RegisterInfoForm(infoForm: TInvokeInfoForm);
- procedure InvokeInfoForm(aSceneBuffer: TgxSceneBuffer; Modal: Boolean);
- function GetCurrentRenderingObject: TgxBaseSceneObject;
- var
- vCounterFrequency: Int64;
- {$IFNDEF USE_MULTITHREAD}
- var
- {$ELSE}
- threadvar
- {$ENDIF}
- vCurrentRenderingObject: TgxBaseSceneObject;
- // ------------------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------------------
- function GetCurrentRenderingObject: TgxBaseSceneObject;
- begin
- Result := vCurrentRenderingObject;
- end;
- procedure AxesBuildList(var rci: TgxRenderContextInfo; pattern: Word; AxisLen: Single);
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL_GREMEDY_string_marker then
- GL_StringMarkerGREMEDY(13, 'AxesBuildList');
- {$ENDIF}
- with rci.gxStates do
- begin
- Disable(stLighting);
- if not rci.ignoreBlendingRequests then
- begin
- Enable(stBlend);
- SetBlendFunc(bfSrcAlpha, bfOneMinusSrcAlpha);
- end;
- LineWidth := 1;
- Enable(stLineStipple);
- LineStippleFactor := 1;
- LineStipplePattern := pattern;
- DepthWriteMask := False;
- DepthFunc := cfLEqual;
- if rci.bufferDepthTest then
- Enable(stDepthTest);
- end;
- glBegin(GL_LINES);
- glColor3f(0.5, 0.0, 0.0);
- glVertex3f(0, 0, 0);
- glVertex3f(-AxisLen, 0, 0);
- glColor3f(1.0, 0.0, 0.0);
- glVertex3f(0, 0, 0);
- glVertex3f(AxisLen, 0, 0);
- glColor3f(0.0, 0.5, 0.0);
- glVertex3f(0, 0, 0);
- glVertex3f(0, -AxisLen, 0);
- glColor3f(0.0, 1.0, 0.0);
- glVertex3f(0, 0, 0);
- glVertex3f(0, AxisLen, 0);
- glColor3f(0.0, 0.0, 0.5);
- glVertex3f(0, 0, 0);
- glVertex3f(0, 0, -AxisLen);
- glColor3f(0.0, 0.0, 1.0);
- glVertex3f(0, 0, 0);
- glVertex3f(0, 0, AxisLen);
- glEnd;
- end;
- var
- vInfoForm: TInvokeInfoForm = nil;
- procedure RegisterInfoForm(infoForm: TInvokeInfoForm);
- begin
- vInfoForm := infoForm;
- end;
- procedure InvokeInfoForm(aSceneBuffer: TgxSceneBuffer; Modal: Boolean);
- begin
- if Assigned(vInfoForm) then
- vInfoForm(aSceneBuffer, Modal)
- else
- InformationDlg('InfoForm not available.');
- end;
- // ------------------ internal global routines ----------------------------------
- var
- vBaseSceneObjectNameChangeEvent: TNotifyEvent;
- vBehaviourNameChangeEvent: TNotifyEvent;
- procedure RegisterBaseSceneObjectNameChangeEvent(notifyEvent: TNotifyEvent);
- begin
- vBaseSceneObjectNameChangeEvent := notifyEvent;
- end;
- procedure DeRegisterBaseSceneObjectNameChangeEvent(notifyEvent: TNotifyEvent);
- begin
- vBaseSceneObjectNameChangeEvent := nil;
- end;
- procedure RegisterBehaviourNameChangeEvent(notifyEvent: TNotifyEvent);
- begin
- vBehaviourNameChangeEvent := notifyEvent;
- end;
- procedure DeRegisterBehaviourNameChangeEvent(notifyEvent: TNotifyEvent);
- begin
- vBehaviourNameChangeEvent := nil;
- end;
- // ------------------
- // ------------------ TgxBaseSceneObject ------------------
- // ------------------
- constructor TgxBaseSceneObject.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FListHandle := TgxListHandle.Create;
- FObjectStyle := [];
- FChanges := [ocTransformation, ocStructure, ocAbsoluteMatrix, ocInvAbsoluteMatrix];
- FPosition := TgxCoordinates.CreateInitialized(Self, NullHmgPoint, csPoint);
- FRotation := TgxCoordinates.CreateInitialized(Self, NullHmgVector, csVector);
- FDirection := TgxCoordinates.CreateInitialized(Self, ZHmgVector, csVector);
- FUp := TgxCoordinates.CreateInitialized(Self, YHmgVector, csVector);
- FScaling := TgxCoordinates.CreateInitialized(Self, XYZHmgVector, csVector);
- FLocalMatrix := IdentityHmgMatrix;
- FVisible := True;
- FPickable := True;
- FObjectsSorting := osInherited;
- FVisibilityCulling := vcInherited;
- FChildren := TgxPersistentObjectList.Create;
- FBBChanges := [oBBcChild, oBBcStructure];
- FBoundingBoxPersonalUnscaled := NullBoundingBox;
- FBoundingBoxOfChildren := NullBoundingBox;
- FBoundingBoxIncludingChildren := NullBoundingBox;
- distList := TgxSingleList.Create;
- objList := TgxPersistentObjectList.Create;
- end;
- constructor TgxBaseSceneObject.CreateAsChild(aParentOwner: TgxBaseSceneObject);
- begin
- Create(aParentOwner);
- aParentOwner.AddChild(Self);
- end;
- destructor TgxBaseSceneObject.Destroy;
- begin
- DeleteChildCameras;
- FEffects.Free;
- FBehaviours.Free;
- FListHandle.Free;
- FPosition.Free;
- FRotation.Free;
- FDirection.Free;
- FUp.Free;
- FScaling.Free;
- if Assigned(FParent) then
- FParent.Remove(Self, False);
- DeleteChildren;
- FChildren.Free;
- objList.Free;
- distList.Free;
- inherited Destroy;
- end;
- function TgxBaseSceneObject.GetHandle(var rci: TgxRenderContextInfo): Cardinal;
- begin
- // Special case.. dirty trixxors
- if not Assigned(FListHandle) then
- begin
- Result := 0;
- Exit;
- end;
- Result := FListHandle.Handle;
- if Result = 0 then
- Result := FListHandle.AllocateHandle;
- if ocStructure in FChanges then
- begin
- ClearStructureChanged;
- FListHandle.NotifyChangesOfData;
- end;
- if FListHandle.IsDataNeedUpdate then
- begin
- rci.gxStates.NewList(Result, GL_COMPILE);
- // try
- BuildList(rci);
- // finally
- rci.gxStates.EndList;
- // end;
- FListHandle.NotifyDataUpdated;
- end;
- end;
- function TgxBaseSceneObject.ListHandleAllocated: Boolean;
- begin
- Result := Assigned(FListHandle) and (FListHandle.Handle <> 0) and not(ocStructure in FChanges);
- end;
- procedure TgxBaseSceneObject.DestroyHandle;
- begin
- if Assigned(FListHandle) then
- FListHandle.DestroyHandle;
- end;
- procedure TgxBaseSceneObject.DestroyHandles;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- Children[i].DestroyHandles;
- DestroyHandle;
- end;
- procedure TgxBaseSceneObject.SetBBChanges(const Value: TObjectBBChanges);
- begin
- if Value <> FBBChanges then
- begin
- FBBChanges := Value;
- if Assigned(FParent) then
- FParent.BBChanges := FParent.BBChanges + [oBBcChild];
- end;
- end;
- function TgxBaseSceneObject.Blended: Boolean;
- begin
- Result := False;
- end;
- procedure TgxBaseSceneObject.BeginUpdate;
- begin
- Inc(FUpdateCount);
- end;
- procedure TgxBaseSceneObject.EndUpdate;
- begin
- if FUpdateCount > 0 then
- begin
- Dec(FUpdateCount);
- if FUpdateCount = 0 then
- NotifyChange(Self);
- end
- else
- Assert(False, strUnBalancedBeginEndUpdate);
- end;
- procedure TgxBaseSceneObject.BuildList(var rci: TgxRenderContextInfo);
- begin
- // nothing
- end;
- procedure TgxBaseSceneObject.DeleteChildCameras;
- var
- i: Integer;
- child: TgxBaseSceneObject;
- begin
- i := 0;
- while i < FChildren.Count do
- begin
- child := TgxBaseSceneObject(FChildren.List^[i]);
- child.DeleteChildCameras;
- if child is TgxCamera then
- begin
- Remove(child, True);
- child.Free;
- end
- else
- Inc(i);
- end;
- end;
- procedure TgxBaseSceneObject.DeleteChildren;
- var
- child: TgxBaseSceneObject;
- begin
- DeleteChildCameras;
- if Assigned(FScene) then
- FScene.RemoveLights(Self);
- while FChildren.Count > 0 do
- begin
- child := TgxBaseSceneObject(FChildren.Pop);
- child.FParent := nil;
- child.Free;
- end;
- BBChanges := BBChanges + [oBBcChild];
- end;
- procedure TgxBaseSceneObject.Loaded;
- begin
- inherited;
- FPosition.W := 1;
- if Assigned(FBehaviours) then
- FBehaviours.Loaded;
- if Assigned(FEffects) then
- FEffects.Loaded;
- end;
- procedure TgxBaseSceneObject.DefineProperties(Filer: TFiler);
- begin
- inherited;
- { FOriginalFiler := Filer; }
- Filer.DefineBinaryProperty('BehavioursData', ReadBehaviours, WriteBehaviours,
- (Assigned(FBehaviours) and (FBehaviours.Count > 0)));
- Filer.DefineBinaryProperty('EffectsData', ReadEffects, WriteEffects,
- (Assigned(FEffects) and (FEffects.Count > 0)));
- { FOriginalFiler:=nil; }
- end;
- procedure TgxBaseSceneObject.WriteBehaviours(stream: TStream);
- var
- writer: TWriter;
- begin
- writer := TWriter.Create(stream, 16384);
- try
- Behaviours.WriteToFiler(writer);
- finally
- writer.Free;
- end;
- end;
- procedure TgxBaseSceneObject.ReadBehaviours(stream: TStream);
- var
- reader: TReader;
- begin
- reader := TReader.Create(stream, 16384);
- { with TReader(FOriginalFiler) do }
- try
- { reader.Root := Root;
- reader.OnError := OnError;
- reader.OnFindMethod := OnFindMethod;
- reader.OnSetName := OnSetName;
- reader.OnReferenceName := OnReferenceName;
- reader.OnAncestorNotFound := OnAncestorNotFound;
- reader.OnCreateComponent := OnCreateComponent;
- reader.OnFindComponentClass := OnFindComponentClass; }
- Behaviours.ReadFromFiler(reader);
- finally
- reader.Free;
- end;
- end;
- procedure TgxBaseSceneObject.WriteEffects(stream: TStream);
- var
- writer: TWriter;
- begin
- writer := TWriter.Create(stream, 16384);
- try
- Effects.WriteToFiler(writer);
- finally
- writer.Free;
- end;
- end;
- procedure TgxBaseSceneObject.ReadEffects(stream: TStream);
- var
- reader: TReader;
- begin
- reader := TReader.Create(stream, 16384);
- // with TReader(FOriginalFiler) do
- try
- (* reader.Root := Root;
- reader.OnError := OnError;
- reader.OnFindMethod := OnFindMethod;
- reader.OnSetName := OnSetName;
- reader.OnReferenceName := OnReferenceName;
- reader.OnAncestorNotFound := OnAncestorNotFound;
- reader.OnCreateComponent := OnCreateComponent;
- reader.OnFindComponentClass := OnFindComponentClass; *)
- Effects.ReadFromFiler(reader);
- finally
- reader.Free;
- end;
- end;
- procedure TgxBaseSceneObject.WriteRotations(stream: TStream);
- begin
- stream.Write(FRotation.AsAddress^, 3 * SizeOf(Single));
- end;
- procedure TgxBaseSceneObject.ReadRotations(stream: TStream);
- begin
- stream.Read(FRotation.AsAddress^, 3 * SizeOf(Single));
- end;
- procedure TgxBaseSceneObject.DrawAxes(var rci: TgxRenderContextInfo; pattern: Word);
- begin
- AxesBuildList(rci, pattern, rci.rcci.farClippingDistance - rci.rcci.nearClippingDistance);
- end;
- procedure TgxBaseSceneObject.GetChildren(AProc: TGetChildProc; Root: TComponent);
- var
- i: Integer;
- begin
- for i := 0 to FChildren.Count - 1 do
- if not IsSubComponent(TComponent(FChildren.List^[i])) then
- AProc(TComponent(FChildren.List^[i]));
- end;
- function TgxBaseSceneObject.Get(Index: Integer): TgxBaseSceneObject;
- begin
- Result := TgxBaseSceneObject(FChildren[Index]);
- end;
- function TgxBaseSceneObject.GetCount: Integer;
- begin
- Result := FChildren.Count;
- end;
- function TgxBaseSceneObject.GetDirectAbsoluteMatrix: PMatrix4f;
- begin
- Result := @FAbsoluteMatrix;
- end;
- function TgxBaseSceneObject.HasSubChildren: Boolean;
- var
- i: Integer;
- begin
- Result := False;
- if Count <> 0 then
- for i := 0 to Count - 1 do
- if IsSubComponent(Children[i]) then
- begin
- Result := True;
- Exit;
- end;
- end;
- procedure TgxBaseSceneObject.AddChild(AChild: TgxBaseSceneObject);
- begin
- if Assigned(FScene) then
- FScene.AddLights(AChild);
- FChildren.Add(AChild);
- AChild.FParent := Self;
- AChild.SetScene(FScene);
- TransformationChanged;
- AChild.TransformationChanged;
- AChild.DoOnAddedToParent;
- BBChanges := BBChanges + [oBBcChild];
- end;
- function TgxBaseSceneObject.AddNewChild(AChild: TgxSceneObjectClass): TgxBaseSceneObject;
- begin
- Result := AChild.Create(Owner);
- AddChild(Result);
- end;
- function TgxBaseSceneObject.AddNewChildFirst(AChild: TgxSceneObjectClass): TgxBaseSceneObject;
- begin
- Result := AChild.Create(Owner);
- Insert(0, Result);
- end;
- function TgxBaseSceneObject.GetOrCreateBehaviour(aBehaviour: TgxBehaviourClass): TgxBehaviour;
- begin
- Result := TgxBehaviour(Behaviours.GetOrCreate(aBehaviour));
- end;
- function TgxBaseSceneObject.AddNewBehaviour(aBehaviour: TgxBehaviourClass): TgxBehaviour;
- begin
- Assert(Behaviours.CanAdd(aBehaviour));
- Result := aBehaviour.Create(Behaviours)
- end;
- function TgxBaseSceneObject.GetOrCreateEffect(anEffect: TgxEffectClass): TgxEffect;
- begin
- Result := TgxEffect(Effects.GetOrCreate(anEffect));
- end;
- function TgxBaseSceneObject.AddNewEffect(anEffect: TgxEffectClass): TgxEffect;
- begin
- Assert(Effects.CanAdd(anEffect));
- Result := anEffect.Create(Effects)
- end;
- procedure TgxBaseSceneObject.RebuildMatrix;
- begin
- if ocTransformation in Changes then
- begin
- VectorScale(LeftVector, Scale.x, FLocalMatrix.x);
- VectorScale(FUp.AsVector, Scale.y, FLocalMatrix.y);
- VectorScale(FDirection.AsVector, Scale.z, FLocalMatrix.z);
- SetVector(FLocalMatrix.W, FPosition.AsVector);
- Exclude(FChanges, ocTransformation);
- Include(FChanges, ocAbsoluteMatrix);
- Include(FChanges, ocInvAbsoluteMatrix);
- end;
- end;
- procedure TgxBaseSceneObject.ForceLocalMatrix(const aMatrix: TMatrix4f);
- begin
- FLocalMatrix := aMatrix;
- Exclude(FChanges, ocTransformation);
- Include(FChanges, ocAbsoluteMatrix);
- Include(FChanges, ocInvAbsoluteMatrix);
- end;
- function TgxBaseSceneObject.AbsoluteMatrixAsAddress: PMatrix4f;
- begin
- if ocAbsoluteMatrix in FChanges then
- begin
- RebuildMatrix;
- if Assigned(Parent) { and (not (Parent is TgxSceneRootObject)) } then
- begin
- MatrixMultiply(FLocalMatrix, TgxBaseSceneObject(Parent).AbsoluteMatrixAsAddress^, FAbsoluteMatrix);
- end
- else
- FAbsoluteMatrix := FLocalMatrix;
- Exclude(FChanges, ocAbsoluteMatrix);
- Include(FChanges, ocInvAbsoluteMatrix);
- end;
- Result := @FAbsoluteMatrix;
- end;
- function TgxBaseSceneObject.InvAbsoluteMatrix: TMatrix4f;
- begin
- Result := InvAbsoluteMatrixAsAddress^;
- end;
- function TgxBaseSceneObject.InvAbsoluteMatrixAsAddress: PMatrix4f;
- begin
- if ocInvAbsoluteMatrix in FChanges then
- begin
- if VectorEquals(Scale.DirectVector, XYZHmgVector) then
- begin
- RebuildMatrix;
- if Parent <> nil then
- FInvAbsoluteMatrix := MatrixMultiply(Parent.InvAbsoluteMatrixAsAddress^, AnglePreservingMatrixInvert(FLocalMatrix))
- else
- FInvAbsoluteMatrix := AnglePreservingMatrixInvert(FLocalMatrix);
- end
- else
- begin
- FInvAbsoluteMatrix := AbsoluteMatrixAsAddress^;
- InvertMatrix(FInvAbsoluteMatrix);
- end;
- Exclude(FChanges, ocInvAbsoluteMatrix);
- end;
- Result := @FInvAbsoluteMatrix;
- end;
- function TgxBaseSceneObject.GetAbsoluteMatrix: TMatrix4f;
- begin
- Result := AbsoluteMatrixAsAddress^;
- end;
- procedure TgxBaseSceneObject.SetAbsoluteMatrix(const Value: TMatrix4f);
- begin
- if not MatrixEquals(Value, FAbsoluteMatrix) then
- begin
- FAbsoluteMatrix := Value;
- if Parent <> nil then
- SetMatrix(MatrixMultiply(FAbsoluteMatrix, Parent.InvAbsoluteMatrixAsAddress^))
- else
- SetMatrix(Value);
- end;
- end;
- function TgxBaseSceneObject.GetAbsoluteDirection: TVector4f;
- begin
- Result := VectorNormalize(AbsoluteMatrixAsAddress^.z);
- end;
- procedure TgxBaseSceneObject.SetAbsoluteDirection(const v: TVector4f);
- begin
- if Parent <> nil then
- Direction.AsVector := Parent.AbsoluteToLocal(v)
- else
- Direction.AsVector := v;
- end;
- function TgxBaseSceneObject.GetAbsoluteScale: TVector4f;
- begin
- Result.x := AbsoluteMatrixAsAddress^.x.x;
- Result.y := AbsoluteMatrixAsAddress^.y.y;
- Result.z := AbsoluteMatrixAsAddress^.z.z;
- Result.W := 0;
- end;
- procedure TgxBaseSceneObject.SetAbsoluteScale(const Value: TVector4f);
- begin
- if Parent <> nil then
- Scale.AsVector := Parent.AbsoluteToLocal(Value)
- else
- Scale.AsVector := Value;
- end;
- function TgxBaseSceneObject.GetAbsoluteUp: TVector4f;
- begin
- Result := VectorNormalize(AbsoluteMatrixAsAddress^.y);
- end;
- procedure TgxBaseSceneObject.SetAbsoluteUp(const v: TVector4f);
- begin
- if Parent <> nil then
- Up.AsVector := Parent.AbsoluteToLocal(v)
- else
- Up.AsVector := v;
- end;
- function TgxBaseSceneObject.AbsoluteRight: TVector4f;
- begin
- Result := VectorNormalize(AbsoluteMatrixAsAddress^.x);
- end;
- function TgxBaseSceneObject.AbsoluteLeft: TVector4f;
- begin
- Result := VectorNegate(AbsoluteRight);
- end;
- function TgxBaseSceneObject.GetAbsolutePosition: TVector4f;
- begin
- Result := AbsoluteMatrixAsAddress^.W;
- end;
- procedure TgxBaseSceneObject.SetAbsolutePosition(const v: TVector4f);
- begin
- if Assigned(Parent) then
- Position.AsVector := Parent.AbsoluteToLocal(v)
- else
- Position.AsVector := v;
- end;
- function TgxBaseSceneObject.AbsolutePositionAsAddress: PVector4f;
- begin
- Result := @AbsoluteMatrixAsAddress^.W;
- end;
- function TgxBaseSceneObject.AbsoluteXVector: TVector4f;
- begin
- AbsoluteMatrixAsAddress;
- SetVector(Result, PAffineVector(@FAbsoluteMatrix.x)^);
- end;
- function TgxBaseSceneObject.AbsoluteYVector: TVector4f;
- begin
- AbsoluteMatrixAsAddress;
- SetVector(Result, PAffineVector(@FAbsoluteMatrix.y)^);
- end;
- function TgxBaseSceneObject.AbsoluteZVector: TVector4f;
- begin
- AbsoluteMatrixAsAddress;
- SetVector(Result, PAffineVector(@FAbsoluteMatrix.z)^);
- end;
- function TgxBaseSceneObject.AbsoluteToLocal(const v: TVector4f): TVector4f;
- begin
- Result := VectorTransform(v, InvAbsoluteMatrixAsAddress^);
- end;
- function TgxBaseSceneObject.AbsoluteToLocal(const v: TAffineVector): TAffineVector;
- begin
- Result := VectorTransform(v, InvAbsoluteMatrixAsAddress^);
- end;
- function TgxBaseSceneObject.LocalToAbsolute(const v: TVector4f): TVector4f;
- begin
- Result := VectorTransform(v, AbsoluteMatrixAsAddress^);
- end;
- function TgxBaseSceneObject.LocalToAbsolute(const v: TAffineVector): TAffineVector;
- begin
- Result := VectorTransform(v, AbsoluteMatrixAsAddress^);
- end;
- function TgxBaseSceneObject.Right: TVector4f;
- begin
- Result := VectorCrossProduct(FDirection.AsVector, FUp.AsVector);
- end;
- function TgxBaseSceneObject.LeftVector: TVector4f;
- begin
- Result := VectorCrossProduct(FUp.AsVector, FDirection.AsVector);
- end;
- function TgxBaseSceneObject.BarycenterAbsolutePosition: TVector4f;
- begin
- Result := AbsolutePosition;
- end;
- function TgxBaseSceneObject.SqrDistanceTo(anObject: TgxBaseSceneObject): Single;
- begin
- if Assigned(anObject) then
- Result := VectorDistance2(AbsolutePosition, anObject.AbsolutePosition)
- else
- Result := 0;
- end;
- function TgxBaseSceneObject.SqrDistanceTo(const pt: TVector4f): Single;
- begin
- Result := VectorDistance2(pt, AbsolutePosition);
- end;
- function TgxBaseSceneObject.DistanceTo(anObject: TgxBaseSceneObject): Single;
- begin
- if Assigned(anObject) then
- Result := VectorDistance(AbsolutePosition, anObject.AbsolutePosition)
- else
- Result := 0;
- end;
- function TgxBaseSceneObject.DistanceTo(const pt: TVector4f): Single;
- begin
- Result := VectorDistance(AbsolutePosition, pt);
- end;
- function TgxBaseSceneObject.BarycenterSqrDistanceTo(const pt: TVector4f): Single;
- var
- d: TVector4f;
- begin
- d := BarycenterAbsolutePosition;
- Result := VectorDistance2(d, pt);
- end;
- function TgxBaseSceneObject.AxisAlignedDimensions: TVector4f;
- begin
- Result := AxisAlignedDimensionsUnscaled();
- ScaleVector(Result, Scale.AsVector);
- end;
- function TgxBaseSceneObject.AxisAlignedDimensionsUnscaled: TVector4f;
- begin
- Result.x := 0.5;
- Result.y := 0.5;
- Result.z := 0.5;
- Result.W := 0;
- end;
- function TgxBaseSceneObject.AxisAlignedBoundingBox(const AIncludeChilden: Boolean): TAABB;
- var
- i: Integer;
- aabb: TAABB;
- child: TgxBaseSceneObject;
- begin
- SetAABB(Result, AxisAlignedDimensionsUnscaled);
- // not tested for child objects
- if AIncludeChilden then
- begin
- for i := 0 to FChildren.Count - 1 do
- begin
- child := TgxBaseSceneObject(FChildren.List^[i]);
- aabb := child.AxisAlignedBoundingBoxUnscaled(AIncludeChilden);
- AABBTransform(aabb, child.Matrix^);
- AddAABB(Result, aabb);
- end;
- end;
- AABBScale(Result, Scale.AsAffineVector);
- end;
- function TgxBaseSceneObject.AxisAlignedBoundingBoxUnscaled(const AIncludeChilden: Boolean): TAABB;
- var
- i: Integer;
- aabb: TAABB;
- begin
- SetAABB(Result, AxisAlignedDimensionsUnscaled);
- // not tested for child objects
- if AIncludeChilden then
- begin
- for i := 0 to FChildren.Count - 1 do
- begin
- aabb := TgxBaseSceneObject(FChildren.List^[i]).AxisAlignedBoundingBoxUnscaled(AIncludeChilden);
- AABBTransform(aabb, TgxBaseSceneObject(FChildren.List^[i]).Matrix^);
- AddAABB(Result, aabb);
- end;
- end;
- end;
- function TgxBaseSceneObject.AxisAlignedBoundingBoxAbsolute(const AIncludeChilden: Boolean;
- const AUseBaryCenter: Boolean): TAABB;
- begin
- Result := BBToAABB(BoundingBoxAbsolute(AIncludeChilden, AUseBaryCenter));
- end;
- function TgxBaseSceneObject.BoundingBox(const AIncludeChilden: Boolean; const AUseBaryCenter: Boolean): THmgBoundingBox;
- var
- CurrentBaryOffset: TVector4f;
- begin
- Result := AABBToBB(AxisAlignedBoundingBox(AIncludeChilden));
- // DaStr: code not tested...
- if AUseBaryCenter then
- begin
- CurrentBaryOffset := VectorSubtract(AbsoluteToLocal(BarycenterAbsolutePosition), Position.AsVector);
- OffsetBBPoint(Result, CurrentBaryOffset);
- end;
- end;
- function TgxBaseSceneObject.BoundingBoxUnscaled(const AIncludeChilden: Boolean; const AUseBaryCenter: Boolean): THmgBoundingBox;
- var
- CurrentBaryOffset: TVector4f;
- begin
- Result := AABBToBB(AxisAlignedBoundingBoxUnscaled(AIncludeChilden));
- // DaStr: code not tested...
- if AUseBaryCenter then
- begin
- CurrentBaryOffset := VectorSubtract(AbsoluteToLocal(BarycenterAbsolutePosition), Position.AsVector);
- OffsetBBPoint(Result, CurrentBaryOffset);
- end;
- end;
- function TgxBaseSceneObject.BoundingBoxAbsolute(const AIncludeChilden: Boolean; const AUseBaryCenter: Boolean): THmgBoundingBox;
- var
- i: Integer;
- CurrentBaryOffset: TVector4f;
- begin
- Result := BoundingBoxUnscaled(AIncludeChilden, False);
- for i := 0 to 7 do
- Result.BBox[i] := LocalToAbsolute(Result.BBox[i]);
- if AUseBaryCenter then
- begin
- CurrentBaryOffset := VectorSubtract(BarycenterAbsolutePosition, AbsolutePosition);
- OffsetBBPoint(Result, CurrentBaryOffset);
- end;
- end;
- function TgxBaseSceneObject.BoundingSphereRadius: Single;
- begin
- Result := VectorLength(AxisAlignedDimensions);
- end;
- function TgxBaseSceneObject.BoundingSphereRadiusUnscaled: Single;
- begin
- Result := VectorLength(AxisAlignedDimensionsUnscaled);
- end;
- function TgxBaseSceneObject.PointInObject(const point: TVector4f): Boolean;
- var
- localPt, dim: TVector4f;
- begin
- dim := AxisAlignedDimensions;
- localPt := VectorTransform(point, InvAbsoluteMatrix);
- Result := (Abs(localPt.x * Scale.x) <= dim.x) and (Abs(localPt.y * Scale.y) <= dim.y) and (Abs(localPt.z * Scale.z) <= dim.z);
- end;
- procedure TgxBaseSceneObject.CalculateBoundingBoxPersonalUnscaled(var ANewBoundingBox: THmgBoundingBox);
- begin
- // Using the standard method to get the local BB.
- ANewBoundingBox := AABBToBB(AxisAlignedBoundingBoxUnscaled(False));
- OffsetBBPoint(ANewBoundingBox, AbsoluteToLocal(BarycenterAbsolutePosition));
- end;
- function TgxBaseSceneObject.BoundingBoxPersonalUnscaledEx: THmgBoundingBox;
- begin
- if oBBcStructure in FBBChanges then
- begin
- CalculateBoundingBoxPersonalUnscaled(FBoundingBoxPersonalUnscaled);
- Exclude(FBBChanges, oBBcStructure);
- end;
- Result := FBoundingBoxPersonalUnscaled;
- end;
- function TgxBaseSceneObject.AxisAlignedBoundingBoxAbsoluteEx: TAABB;
- var
- pBB: THmgBoundingBox;
- begin
- pBB := BoundingBoxIncludingChildrenEx;
- BBTransform(pBB, AbsoluteMatrix);
- Result := BBToAABB(pBB);
- end;
- function TgxBaseSceneObject.AxisAlignedBoundingBoxEx: TAABB;
- begin
- Result := BBToAABB(BoundingBoxIncludingChildrenEx);
- AABBScale(Result, Scale.AsAffineVector);
- end;
- function TgxBaseSceneObject.BoundingBoxOfChildrenEx: THmgBoundingBox;
- var
- i: Integer;
- pBB: THmgBoundingBox;
- begin
- if oBBcChild in FBBChanges then
- begin
- // Computing
- FBoundingBoxOfChildren := NullBoundingBox;
- for i := 0 to FChildren.Count - 1 do
- begin
- pBB := TgxBaseSceneObject(FChildren.List^[i]).BoundingBoxIncludingChildrenEx;
- if not BoundingBoxesAreEqual(@pBB, @NullBoundingBox) then
- begin
- // transformation with local matrix
- BBTransform(pBB, TgxBaseSceneObject(FChildren.List^[i]).Matrix^);
- if BoundingBoxesAreEqual(@FBoundingBoxOfChildren, @NullBoundingBox) then
- FBoundingBoxOfChildren := pBB
- else
- AddBB(FBoundingBoxOfChildren, pBB);
- end;
- end;
- Exclude(FBBChanges, oBBcChild);
- end;
- Result := FBoundingBoxOfChildren;
- end;
- function TgxBaseSceneObject.BoundingBoxIncludingChildrenEx: THmgBoundingBox;
- var
- pBB: THmgBoundingBox;
- begin
- if (oBBcStructure in FBBChanges) or (oBBcChild in FBBChanges) then
- begin
- pBB := BoundingBoxPersonalUnscaledEx;
- if BoundingBoxesAreEqual(@pBB, @NullBoundingBox) then
- FBoundingBoxIncludingChildren := BoundingBoxOfChildrenEx
- else
- begin
- FBoundingBoxIncludingChildren := pBB;
- pBB := BoundingBoxOfChildrenEx;
- if not BoundingBoxesAreEqual(@pBB, @NullBoundingBox) then
- AddBB(FBoundingBoxIncludingChildren, pBB);
- end;
- end;
- Result := FBoundingBoxIncludingChildren;
- end;
- function TgxBaseSceneObject.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
- intersectNormal: PVector4f = nil): Boolean;
- var
- i1, i2, absPos: TVector4f;
- begin
- SetVector(absPos, AbsolutePosition);
- if RayCastSphereIntersect(rayStart, rayVector, absPos, BoundingSphereRadius, i1, i2) > 0 then
- begin
- Result := True;
- if Assigned(intersectPoint) then
- SetVector(intersectPoint^, i1);
- if Assigned(intersectNormal) then
- begin
- SubtractVector(i1, absPos);
- NormalizeVector(i1);
- SetVector(intersectNormal^, i1);
- end;
- end
- else
- Result := False;
- end;
- function TgxBaseSceneObject.GenerateSilhouette(const SilhouetteParameters: TgxSilhouetteParameters): TgxSilhouette;
- const
- cNbSegments = 21;
- var
- i, j: Integer;
- d, r, vr, s, c, angleFactor: Single;
- sVec, tVec: TAffineVector;
- begin
- r := BoundingSphereRadiusUnscaled;
- d := VectorLength(silhouetteParameters.SeenFrom);
- // determine visible radius
- case silhouetteParameters.Style of
- ssOmni:
- vr := SphereVisibleRadius(d, r);
- ssParallel:
- vr := r;
- else
- Assert(False);
- vr := r;
- end;
- // determine a local orthonormal matrix, viewer-oriented
- sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, XVector);
- if VectorLength(sVec) < 1E-3 then
- sVec := VectorCrossProduct(silhouetteParameters.SeenFrom, YVector);
- tVec := VectorCrossProduct(silhouetteParameters.SeenFrom, sVec);
- NormalizeVector(sVec);
- NormalizeVector(tVec);
- // generate the silhouette (outline and capping)
- Result := TgxSilhouette.Create;
- angleFactor := (2 * PI) / cNbSegments;
- vr := vr * 0.98;
- for i := 0 to cNbSegments - 1 do
- begin
- SinCosine(i * angleFactor, vr, s, c);
- Result.Vertices.AddPoint(VectorCombine(sVec, tVec, s, c));
- j := (i + 1) mod cNbSegments;
- Result.Indices.Add(i, j);
- if silhouetteParameters.CappingRequired then
- Result.CapIndices.Add(cNbSegments, i, j)
- end;
- if silhouetteParameters.CappingRequired then
- Result.Vertices.Add(NullHmgPoint);
- end;
- procedure TgxBaseSceneObject.Assign(Source: TPersistent);
- var
- i: Integer;
- child, newChild: TgxBaseSceneObject;
- begin
- if Assigned(Source) and (Source is TgxBaseSceneObject) then
- begin
- DestroyHandles;
- FVisible := TgxBaseSceneObject(Source).FVisible;
- TgxBaseSceneObject(Source).RebuildMatrix;
- SetMatrix(TgxBaseSceneObject(Source).FLocalMatrix);
- FShowAxes := TgxBaseSceneObject(Source).FShowAxes;
- FObjectsSorting := TgxBaseSceneObject(Source).FObjectsSorting;
- FVisibilityCulling := TgxBaseSceneObject(Source).FVisibilityCulling;
- FRotation.Assign(TgxBaseSceneObject(Source).FRotation);
- DeleteChildren;
- if Assigned(Scene) then
- Scene.BeginUpdate;
- if Assigned(TgxBaseSceneObject(Source).FChildren) then
- begin
- for i := 0 to TgxBaseSceneObject(Source).FChildren.Count - 1 do
- begin
- child := TgxBaseSceneObject(TgxBaseSceneObject(Source).FChildren[i]);
- newChild := AddNewChild(TgxSceneObjectClass(child.ClassType));
- newChild.Assign(child);
- end;
- end;
- if Assigned(Scene) then
- Scene.EndUpdate;
- OnProgress := TgxBaseSceneObject(Source).OnProgress;
- if Assigned(TgxBaseSceneObject(Source).FBehaviours) then
- Behaviours.Assign(TgxBaseSceneObject(Source).Behaviours)
- else
- FreeAndNil(FBehaviours);
- if Assigned(TgxBaseSceneObject(Source).FEffects) then
- Effects.Assign(TgxBaseSceneObject(Source).Effects)
- else
- FreeAndNil(FEffects);
- Tag := TgxBaseSceneObject(Source).Tag;
- FTagFloat := TgxBaseSceneObject(Source).FTagFloat;
- end
- else
- inherited Assign(Source);
- end;
- function TgxBaseSceneObject.IsUpdating: Boolean;
- begin
- Result := (FUpdateCount <> 0) or (csReading in ComponentState);
- end;
- function TgxBaseSceneObject.GetParentComponent: TComponent;
- begin
- if FParent is TgxSceneRootObject then
- Result := FScene
- else
- Result := FParent;
- end;
- function TgxBaseSceneObject.HasParent: Boolean;
- begin
- Result := Assigned(FParent);
- end;
- procedure TgxBaseSceneObject.Lift(ADistance: Single);
- begin
- FPosition.AddScaledVector(ADistance, FUp.AsVector);
- TransformationChanged;
- end;
- procedure TgxBaseSceneObject.Move(ADistance: Single);
- begin
- FPosition.AddScaledVector(ADistance, FDirection.AsVector);
- TransformationChanged;
- end;
- procedure TgxBaseSceneObject.Slide(ADistance: Single);
- begin
- FPosition.AddScaledVector(ADistance, Right);
- TransformationChanged;
- end;
- procedure TgxBaseSceneObject.ResetRotations;
- begin
- FillChar(FLocalMatrix, SizeOf(TMatrix4f), 0);
- FLocalMatrix.x.x := Scale.DirectX;
- FLocalMatrix.y.y := Scale.DirectY;
- FLocalMatrix.z.z := Scale.DirectZ;
- SetVector(FLocalMatrix.W, Position.DirectVector);
- FRotation.DirectVector := NullHmgPoint;
- FDirection.DirectVector := ZHmgVector;
- FUp.DirectVector := YHmgVector;
- TransformationChanged;
- Exclude(FChanges, ocTransformation);
- end;
- procedure TgxBaseSceneObject.ResetAndPitchTurnRoll(const degX, degY, degZ: Single);
- var
- rotMatrix: TMatrix4f;
- v: TVector4f;
- begin
- ResetRotations;
- // set DegX (Pitch)
- rotMatrix := CreateRotationMatrix(Right, degX * cPIdiv180);
- v := VectorTransform(FUp.AsVector, rotMatrix);
- NormalizeVector(v);
- FUp.DirectVector := v;
- v := VectorTransform(FDirection.AsVector, rotMatrix);
- NormalizeVector(v);
- FDirection.DirectVector := v;
- FRotation.DirectX := NormalizeDegAngle(degX);
- // set DegY (Turn)
- rotMatrix := CreateRotationMatrix(FUp.AsVector, degY * cPIdiv180);
- v := VectorTransform(FUp.AsVector, rotMatrix);
- NormalizeVector(v);
- FUp.DirectVector := v;
- v := VectorTransform(FDirection.AsVector, rotMatrix);
- NormalizeVector(v);
- FDirection.DirectVector := v;
- FRotation.DirectY := NormalizeDegAngle(degY);
- // set DegZ (Roll)
- rotMatrix := CreateRotationMatrix(Direction.AsVector, degZ * cPIdiv180);
- v := VectorTransform(FUp.AsVector, rotMatrix);
- NormalizeVector(v);
- FUp.DirectVector := v;
- v := VectorTransform(FDirection.AsVector, rotMatrix);
- NormalizeVector(v);
- FDirection.DirectVector := v;
- FRotation.DirectZ := NormalizeDegAngle(degZ);
- TransformationChanged;
- NotifyChange(Self);
- end;
- procedure TgxBaseSceneObject.RotateAbsolute(const rx, ry, rz: Single);
- var
- resMat: TMatrix4f;
- v: TAffineVector;
- begin
- resMat := Matrix^;
- // No we build rotation matrices and use them to rotate the obj
- if rx <> 0 then
- begin
- SetVector(v, AbsoluteToLocal(XVector));
- resMat := MatrixMultiply(CreateRotationMatrix(v, -DegToRadian(rx)), resMat);
- end;
- if ry <> 0 then
- begin
- SetVector(v, AbsoluteToLocal(YVector));
- resMat := MatrixMultiply(CreateRotationMatrix(v, -DegToRadian(ry)), resMat);
- end;
- if rz <> 0 then
- begin
- SetVector(v, AbsoluteToLocal(ZVector));
- resMat := MatrixMultiply(CreateRotationMatrix(v, -DegToRadian(rz)), resMat);
- end;
- SetMatrix(resMat);
- end;
- procedure TgxBaseSceneObject.RotateAbsolute(const axis: TAffineVector; angle: Single);
- var
- v: TAffineVector;
- begin
- if angle <> 0 then
- begin
- SetVector(v, AbsoluteToLocal(axis));
- SetMatrix(MatrixMultiply(CreateRotationMatrix(v, DegToRadian(angle)), Matrix^));
- end;
- end;
- procedure TgxBaseSceneObject.Pitch(angle: Single);
- var
- r: Single;
- rightVector: TVector4f;
- begin
- FIsCalculating := True;
- try
- angle := -DegToRad(angle);
- rightVector := Right;
- FUp.Rotate(rightVector, angle);
- FUp.Normalize;
- FDirection.Rotate(rightVector, angle);
- FDirection.Normalize;
- r := -RadToDeg(ArcTan2(FDirection.y, VectorLength(FDirection.x, FDirection.z)));
- if FDirection.x < 0 then
- if FDirection.y < 0 then
- r := 180 - r
- else
- r := -180 - r;
- FRotation.x := r;
- finally
- FIsCalculating := False;
- end;
- TransformationChanged;
- end;
- procedure TgxBaseSceneObject.SetPitchAngle(aValue: Single);
- var
- diff: Single;
- rotMatrix: TMatrix4f;
- begin
- if aValue <> FRotation.x then
- begin
- if not(csLoading in ComponentState) then
- begin
- FIsCalculating := True;
- // try
- diff := DegToRadian(FRotation.x - aValue);
- rotMatrix := CreateRotationMatrix(Right, diff);
- FUp.DirectVector := VectorTransform(FUp.AsVector, rotMatrix);
- FUp.Normalize;
- FDirection.DirectVector := VectorTransform(FDirection.AsVector, rotMatrix);
- FDirection.Normalize;
- TransformationChanged;
- // finally
- FIsCalculating := False;
- // end;
- end;
- FRotation.DirectX := NormalizeDegAngle(aValue);
- end;
- end;
- // Roll
- //
- procedure TgxBaseSceneObject.Roll(angle: Single);
- var
- r: Single;
- rightVector, directionVector: TVector4f;
- begin
- FIsCalculating := True;
- try
- angle := DegToRadian(angle);
- directionVector := Direction.AsVector;
- FUp.Rotate(directionVector, angle);
- FUp.Normalize;
- FDirection.Rotate(directionVector, angle);
- FDirection.Normalize;
- // calculate new rotation angle from vectors
- rightVector := Right;
- r := -RadToDeg(ArcTan2(rightVector.y, VectorLength(rightVector.x, rightVector.z)));
- if rightVector.x < 0 then
- if rightVector.y < 0 then
- r := 180 - r
- else
- r := -180 - r;
- FRotation.z := r;
- finally
- FIsCalculating := False;
- end;
- TransformationChanged;
- end;
- procedure TgxBaseSceneObject.SetRollAngle(aValue: Single);
- var
- diff: Single;
- rotMatrix: TMatrix4f;
- begin
- if aValue <> FRotation.z then
- begin
- if not(csLoading in ComponentState) then
- begin
- FIsCalculating := True;
- // try
- diff := DegToRadian(FRotation.z - aValue);
- rotMatrix := CreateRotationMatrix(Direction.AsVector, diff);
- FUp.DirectVector := VectorTransform(FUp.AsVector, rotMatrix);
- FUp.Normalize;
- FDirection.DirectVector := VectorTransform(FDirection.AsVector, rotMatrix);
- FDirection.Normalize;
- TransformationChanged;
- // finally
- FIsCalculating := False;
- // end;
- end;
- FRotation.DirectZ := NormalizeDegAngle(aValue);
- end;
- end;
- procedure TgxBaseSceneObject.Turn(angle: Single);
- var
- r: Single;
- upVector: TVector4f;
- begin
- FIsCalculating := True;
- try
- angle := DegToRadian(angle);
- upVector := Up.AsVector;
- FUp.Rotate(upVector, angle);
- FUp.Normalize;
- FDirection.Rotate(upVector, angle);
- FDirection.Normalize;
- r := -RadToDeg(ArcTan2(FDirection.x, VectorLength(FDirection.y, FDirection.z)));
- if FDirection.x < 0 then
- if FDirection.y < 0 then
- r := 180 - r
- else
- r := -180 - r;
- FRotation.y := r;
- finally
- FIsCalculating := False;
- end;
- TransformationChanged;
- end;
- procedure TgxBaseSceneObject.SetTurnAngle(aValue: Single);
- var
- diff: Single;
- rotMatrix: TMatrix4f;
- begin
- if aValue <> FRotation.y then
- begin
- if not(csLoading in ComponentState) then
- begin
- FIsCalculating := True;
- // try
- diff := DegToRadian(FRotation.y - aValue);
- rotMatrix := CreateRotationMatrix(Up.AsVector, diff);
- FUp.DirectVector := VectorTransform(FUp.AsVector, rotMatrix);
- FUp.Normalize;
- FDirection.DirectVector := VectorTransform(FDirection.AsVector, rotMatrix);
- FDirection.Normalize;
- TransformationChanged;
- // finally
- FIsCalculating := False;
- // end;
- end;
- FRotation.DirectY := NormalizeDegAngle(aValue);
- end;
- end;
- procedure TgxBaseSceneObject.SetRotation(aRotation: TgxCoordinates);
- begin
- FRotation.Assign(aRotation);
- TransformationChanged;
- end;
- function TgxBaseSceneObject.GetPitchAngle: Single;
- begin
- Result := FRotation.x;
- end;
- function TgxBaseSceneObject.GetTurnAngle: Single;
- begin
- Result := FRotation.y;
- end;
- function TgxBaseSceneObject.GetRollAngle: Single;
- begin
- Result := FRotation.z;
- end;
- procedure TgxBaseSceneObject.PointTo(const ATargetObject: TgxBaseSceneObject; const AUpVector: TVector4f);
- begin
- PointTo(ATargetObject.AbsolutePosition, AUpVector);
- end;
- procedure TgxBaseSceneObject.PointTo(const AAbsolutePosition, AUpVector: TVector4f);
- var
- absDir, absRight, absUp: TVector4f;
- begin
- // first compute absolute attitude for pointing
- absDir := VectorSubtract(AAbsolutePosition, Self.AbsolutePosition);
- NormalizeVector(absDir);
- absRight := VectorCrossProduct(absDir, AUpVector);
- NormalizeVector(absRight);
- absUp := VectorCrossProduct(absRight, absDir);
- // convert absolute to local and adjust object
- if Parent <> nil then
- begin
- FDirection.AsVector := Parent.AbsoluteToLocal(absDir);
- FUp.AsVector := Parent.AbsoluteToLocal(absUp);
- end
- else
- begin
- FDirection.AsVector := absDir;
- FUp.AsVector := absUp;
- end;
- TransformationChanged
- end;
- procedure TgxBaseSceneObject.SetShowAxes(aValue: Boolean);
- begin
- if FShowAxes <> aValue then
- begin
- FShowAxes := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.SetScaling(aValue: TgxCoordinates);
- begin
- FScaling.Assign(aValue);
- TransformationChanged;
- end;
- procedure TgxBaseSceneObject.SetName(const NewName: TComponentName);
- begin
- if Name <> NewName then
- begin
- inherited SetName(NewName);
- if Assigned(vBaseSceneObjectNameChangeEvent) then
- vBaseSceneObjectNameChangeEvent(Self);
- end;
- end;
- procedure TgxBaseSceneObject.SetParent(const val: TgxBaseSceneObject);
- begin
- MoveTo(val);
- end;
- function TgxBaseSceneObject.GetIndex: Integer;
- begin
- if Assigned(FParent) then
- Result := FParent.FChildren.IndexOf(Self)
- else
- Result := -1;
- end;
- function TgxBaseSceneObject.GetLocalMatrix: PMatrix4f;
- begin
- Result := @FLocalMatrix;
- end;
- procedure TgxBaseSceneObject.SetIndex(aValue: Integer);
- var
- LCount: Integer;
- parentBackup: TgxBaseSceneObject;
- begin
- if Assigned(FParent) then
- begin
- if aValue < 0 then
- aValue := 0;
- LCount := FParent.Count;
- if aValue >= LCount then
- aValue := LCount - 1;
- if aValue <> Index then
- begin
- if Assigned(FScene) then
- FScene.BeginUpdate;
- parentBackup := FParent;
- parentBackup.Remove(Self, False);
- parentBackup.Insert(aValue, Self);
- if Assigned(FScene) then
- FScene.EndUpdate;
- end;
- end;
- end;
- procedure TgxBaseSceneObject.SetParentComponent(Value: TComponent);
- begin
- inherited;
- if Value = FParent then
- Exit;
- if Value is TgxScene then
- SetParent(TgxScene(Value).Objects)
- else if Value is TgxBaseSceneObject then
- SetParent(TgxBaseSceneObject(Value))
- else
- SetParent(nil);
- end;
- procedure TgxBaseSceneObject.StructureChanged;
- begin
- if not(ocStructure in FChanges) then
- begin
- Include(FChanges, ocStructure);
- NotifyChange(Self);
- end
- else if osDirectDraw in ObjectStyle then
- NotifyChange(Self);
- end;
- procedure TgxBaseSceneObject.ClearStructureChanged;
- begin
- Exclude(FChanges, ocStructure);
- SetBBChanges(BBChanges + [oBBcStructure]);
- end;
- procedure TgxBaseSceneObject.RecTransformationChanged;
- var
- i: Integer;
- List: PgxPointerObjectList;
- matSet: TObjectChanges;
- begin
- matSet := [ocAbsoluteMatrix, ocInvAbsoluteMatrix];
- if matSet * FChanges <> matSet then
- begin
- FChanges := FChanges + matSet;
- List := FChildren.List;
- for i := 0 to FChildren.Count - 1 do
- TgxBaseSceneObject(List^[i]).RecTransformationChanged;
- end;
- end;
- procedure TgxBaseSceneObject.TransformationChanged;
- begin
- if not(ocTransformation in FChanges) then
- begin
- Include(FChanges, ocTransformation);
- RecTransformationChanged;
- if not(csLoading in ComponentState) then
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.MoveTo(newParent: TgxBaseSceneObject);
- begin
- if newParent = FParent then
- Exit;
- if Assigned(FParent) then
- begin
- FParent.Remove(Self, False);
- FParent := nil;
- end;
- if Assigned(newParent) then
- newParent.AddChild(Self)
- else
- SetScene(nil);
- end;
- procedure TgxBaseSceneObject.MoveUp;
- begin
- if Assigned(Parent) then
- Parent.MoveChildUp(Parent.IndexOfChild(Self));
- end;
- procedure TgxBaseSceneObject.MoveDown;
- begin
- if Assigned(Parent) then
- Parent.MoveChildDown(Parent.IndexOfChild(Self));
- end;
- procedure TgxBaseSceneObject.MoveFirst;
- begin
- if Assigned(Parent) then
- Parent.MoveChildFirst(Parent.IndexOfChild(Self));
- end;
- procedure TgxBaseSceneObject.MoveLast;
- begin
- if Assigned(Parent) then
- Parent.MoveChildLast(Parent.IndexOfChild(Self));
- end;
- procedure TgxBaseSceneObject.MoveObjectAround(anObject: TgxBaseSceneObject; pitchDelta, turnDelta: Single);
- var
- originalT2C, normalT2C, normalCameraRight, newPos: TVector4f;
- pitchNow, dist: Single;
- begin
- if Assigned(anObject) then
- begin
- // normalT2C points away from the direction the camera is looking
- originalT2C := VectorSubtract(AbsolutePosition, anObject.AbsolutePosition);
- SetVector(normalT2C, originalT2C);
- dist := VectorLength(normalT2C);
- NormalizeVector(normalT2C);
- // normalRight points to the camera's right
- // the camera is pitching around this axis.
- normalCameraRight := VectorCrossProduct(AbsoluteUp, normalT2C);
- if VectorLength(normalCameraRight) < 0.001 then
- SetVector(normalCameraRight, XVector) // arbitrary vector
- else
- NormalizeVector(normalCameraRight);
- // calculate the current pitch.
- // 0 is looking down and PI is looking up
- pitchNow := ArcCos(VectorDotProduct(AbsoluteUp, normalT2C));
- pitchNow := ClampValue(pitchNow + DegToRad(pitchDelta), 0 + 0.025, PI - 0.025);
- // creates a new vector pointing up and then rotate it down
- // into the new position
- SetVector(normalT2C, AbsoluteUp);
- RotateVector(normalT2C, normalCameraRight, -pitchNow);
- RotateVector(normalT2C, AbsoluteUp, -DegToRadian(turnDelta));
- ScaleVector(normalT2C, dist);
- newPos := VectorAdd(AbsolutePosition, VectorSubtract(normalT2C, originalT2C));
- if Assigned(Parent) then
- newPos := Parent.AbsoluteToLocal(newPos);
- Position.AsVector := newPos;
- end;
- end;
- procedure TgxBaseSceneObject.MoveObjectAllAround(anObject: TgxBaseSceneObject; pitchDelta, turnDelta: Single);
- var
- upVector: TVector4f;
- lookat: TVector4f;
- rightVector: TVector4f;
- tempvector: TVector4f;
- T2C: TVector4f;
- begin
- // if camera has got a target
- if Assigned(anObject) then
- begin
- // vector camera to target
- lookat := VectorNormalize(VectorSubtract(anObject.AbsolutePosition, AbsolutePosition));
- // camera up vector
- upVector := VectorNormalize(AbsoluteUp);
- // if upvector and lookat vector are colinear, it is necessary to compute new up vector
- if Abs(VectorDotProduct(lookat, upVector)) > 0.99 then
- begin
- // X or Y vector use to generate upvector
- SetVector(tempvector, 1, 0, 0);
- // if lookat is colinear to X vector use Y vector to generate upvector
- if Abs(VectorDotProduct(tempvector, lookat)) > 0.99 then
- begin
- SetVector(tempvector, 0, 1, 0);
- end;
- upVector := VectorCrossProduct(tempvector, lookat);
- rightVector := VectorCrossProduct(lookat, upVector);
- end
- else
- begin
- rightVector := VectorCrossProduct(lookat, upVector);
- upVector := VectorCrossProduct(rightVector, lookat);
- end;
- // now the up right and lookat vector are orthogonal
- // vector Target to camera
- T2C := VectorSubtract(AbsolutePosition, anObject.AbsolutePosition);
- RotateVector(T2C, rightVector, DegToRadian(-pitchDelta));
- RotateVector(T2C, upVector, DegToRadian(-turnDelta));
- AbsolutePosition := VectorAdd(anObject.AbsolutePosition, T2C);
- // now update new up vector
- RotateVector(upVector, rightVector, DegToRadian(-pitchDelta));
- AbsoluteUp := upVector;
- AbsoluteDirection := VectorSubtract(anObject.AbsolutePosition, AbsolutePosition);
- end;
- end;
- procedure TgxBaseSceneObject.CoordinateChanged(Sender: TgxCustomCoordinates);
- var
- rightVector: TVector4f;
- begin
- if FIsCalculating then
- Exit;
- FIsCalculating := True;
- try
- if Sender = FDirection then
- begin
- if FDirection.VectorLength = 0 then
- FDirection.DirectVector := ZHmgVector;
- FDirection.Normalize;
- // adjust up vector
- rightVector := VectorCrossProduct(FDirection.AsVector, FUp.AsVector);
- // Rightvector is zero if direction changed exactly by 90 degrees,
- // in this case assume a default vector
- if VectorLength(rightVector) < 1E-5 then
- begin
- rightVector := VectorCrossProduct(ZHmgVector, FUp.AsVector);
- if VectorLength(rightVector) < 1E-5 then
- rightVector := VectorCrossProduct(XHmgVector, FUp.AsVector);
- end;
- FUp.DirectVector := VectorCrossProduct(rightVector, FDirection.AsVector);
- FUp.Normalize;
- end
- else if Sender = FUp then
- begin
- if FUp.VectorLength = 0 then
- FUp.DirectVector := YHmgVector;
- FUp.Normalize;
- // adjust up vector
- rightVector := VectorCrossProduct(FDirection.AsVector, FUp.AsVector);
- // Rightvector is zero if direction changed exactly by 90 degrees,
- // in this case assume a default vector
- if VectorLength(rightVector) < 1E-5 then
- begin
- rightVector := VectorCrossProduct(ZHmgVector, FUp.AsVector);
- if VectorLength(rightVector) < 1E-5 then
- rightVector := VectorCrossProduct(XHmgVector, FUp.AsVector);
- end;
- FDirection.DirectVector := VectorCrossProduct(FUp.AsVector, rightVector);
- FDirection.Normalize;
- end;
- TransformationChanged;
- finally
- FIsCalculating := False;
- end;
- end;
- procedure TgxBaseSceneObject.DoProgress(const progressTime: TgxProgressTimes);
- var
- i: Integer;
- begin
- for i := FChildren.Count - 1 downto 0 do
- TgxBaseSceneObject(FChildren.List^[i]).DoProgress(progressTime);
- if Assigned(FBehaviours) then
- FBehaviours.DoProgress(progressTime);
- if Assigned(FEffects) then
- FEffects.DoProgress(progressTime);
- if Assigned(FOnProgress) then
- with progressTime do
- FOnProgress(Self, deltaTime, newTime);
- end;
- procedure TgxBaseSceneObject.Insert(AIndex: Integer; AChild: TgxBaseSceneObject);
- begin
- with FChildren do
- begin
- if Assigned(AChild.FParent) then
- AChild.FParent.Remove(AChild, False);
- Insert(AIndex, AChild);
- end;
- AChild.FParent := Self;
- if AChild.FScene <> FScene then
- AChild.DestroyHandles;
- AChild.SetScene(FScene);
- if Assigned(FScene) then
- FScene.AddLights(AChild);
- AChild.TransformationChanged;
- AChild.DoOnAddedToParent;
- end;
- procedure TgxBaseSceneObject.Remove(AChild: TgxBaseSceneObject; keepChildren: Boolean);
- var
- i: Integer;
- begin
- if not Assigned(FChildren) then
- Exit;
- if AChild.Parent = Self then
- begin
- if Assigned(FScene) then
- FScene.RemoveLights(AChild);
- if AChild.Owner = Self then
- RemoveComponent(AChild);
- FChildren.Remove(AChild);
- AChild.FParent := nil;
- if keepChildren then
- begin
- BeginUpdate;
- if AChild.Count <> 0 then
- for i := AChild.Count - 1 downto 0 do
- if not IsSubComponent(AChild.Children[i]) then
- AChild.Children[i].MoveTo(Self);
- EndUpdate;
- end
- else
- NotifyChange(Self);
- end;
- end;
- function TgxBaseSceneObject.IndexOfChild(AChild: TgxBaseSceneObject): Integer;
- begin
- Result := FChildren.IndexOf(AChild)
- end;
- function TgxBaseSceneObject.FindChild(const aName: string; ownChildrenOnly: Boolean): TgxBaseSceneObject;
- var
- i: Integer;
- res: TgxBaseSceneObject;
- begin
- res := nil;
- Result := nil;
- for i := 0 to FChildren.Count - 1 do
- begin
- if CompareText(TgxBaseSceneObject(FChildren[i]).Name, aName) = 0 then
- begin
- res := TgxBaseSceneObject(FChildren[i]);
- Break;
- end;
- end;
- if not ownChildrenOnly then
- begin
- for i := 0 to FChildren.Count - 1 do
- with TgxBaseSceneObject(FChildren[i]) do
- begin
- Result := FindChild(aName, ownChildrenOnly);
- if Assigned(Result) then
- Break;
- end;
- end;
- if not Assigned(Result) then
- Result := res;
- end;
- procedure TgxBaseSceneObject.ExchangeChildren(anIndex1, anIndex2: Integer);
- begin
- Assert(Assigned(FChildren), 'No children found!');
- FChildren.Exchange(anIndex1, anIndex2);
- NotifyChange(Self);
- end;
- procedure TgxBaseSceneObject.ExchangeChildrenSafe(anIndex1, anIndex2: Integer);
- begin
- Assert(Assigned(FChildren), 'No children found!');
- if (anIndex1 < FChildren.Count) and (anIndex2 < FChildren.Count) and (anIndex1 > -1) and (anIndex2 > -1) and
- (anIndex1 <> anIndex2) then
- begin
- FChildren.Exchange(anIndex1, anIndex2);
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.MoveChildUp(anIndex: Integer);
- begin
- Assert(Assigned(FChildren), 'No children found!');
- if anIndex > 0 then
- begin
- FChildren.Exchange(anIndex, anIndex - 1);
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.MoveChildDown(anIndex: Integer);
- begin
- Assert(Assigned(FChildren), 'No children found!');
- if anIndex < FChildren.Count - 1 then
- begin
- FChildren.Exchange(anIndex, anIndex + 1);
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.MoveChildFirst(anIndex: Integer);
- begin
- Assert(Assigned(FChildren), 'No children found!');
- if anIndex <> 0 then
- begin
- FChildren.Move(anIndex, 0);
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.MoveChildLast(anIndex: Integer);
- begin
- Assert(Assigned(FChildren), 'No children found!');
- if anIndex <> FChildren.Count - 1 then
- begin
- FChildren.Move(anIndex, FChildren.Count - 1);
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.Render(var ARci: TgxRenderContextInfo);
- var
- shouldRenderSelf, shouldRenderChildren: Boolean;
- aabb: TAABB;
- master: TObject;
- begin
- {$IFDEF USE_OPENGL_DEBUG}
- if GL_GREMEDY_string_marker then
- GL_StringMarkerGREMEDY(Length(Name) + Length('.Render'), PGLChar(String(Name + '.Render')));
- {$ENDIF}
- if (ARci.drawState = dsPicking) and not FPickable then
- Exit;
- // visibility culling determination
- if ARci.VisibilityCulling in [vcObjectBased, vcHierarchical] then
- begin
- if ARci.VisibilityCulling = vcObjectBased then
- begin
- shouldRenderSelf := (osNoVisibilityCulling in ObjectStyle) or
- (not IsVolumeClipped(BarycenterAbsolutePosition, BoundingSphereRadius, ARci.rcci.frustum));
- shouldRenderChildren := Assigned(FChildren);
- end
- else
- begin // vcHierarchical
- aabb := AxisAlignedBoundingBox;
- shouldRenderSelf := (osNoVisibilityCulling in ObjectStyle) or
- (not IsVolumeClipped(aabb.min, aabb.max, ARci.rcci.frustum));
- shouldRenderChildren := shouldRenderSelf and Assigned(FChildren);
- end;
- if not(shouldRenderSelf or shouldRenderChildren) then
- Exit;
- end
- else
- begin
- Assert(ARci.VisibilityCulling in [vcNone, vcInherited], 'Unknown visibility culling option');
- shouldRenderSelf := True;
- shouldRenderChildren := FChildren.Count > 0;
- end;
- // Prepare Matrix and PickList stuff
- ARci.PipeLineTransformation.Push;
- if ocTransformation in FChanges then
- RebuildMatrix;
- if ARci.proxySubObject then
- ARci.PipeLineTransformation.SetModelMatrix(MatrixMultiply(LocalMatrix^, ARci.PipeLineTransformation.ModelMatrix^))
- else
- ARci.PipeLineTransformation.SetModelMatrix(AbsoluteMatrix);
- master := nil;
- if ARci.drawState = dsPicking then
- begin
- if ARci.proxySubObject then
- master := TgxSceneBuffer(ARci.Buffer).FSelector.CurrentObject;
- TgxSceneBuffer(ARci.Buffer).FSelector.CurrentObject := Self;
- end;
- // Start rendering
- if shouldRenderSelf then
- begin
- vCurrentRenderingObject := Self;
- {$IFNDEF USE_OPTIMIZATIONS}
- if FShowAxes then
- DrawAxes(ARci, $CCCC);
- {$ENDIF}
- if Assigned(FEffects) and (FEffects.Count > 0) then
- begin
- ARci.PipeLineTransformation.Push;
- FEffects.RenderPreEffects(ARci);
- ARci.PipeLineTransformation.Pop;
- ARci.PipeLineTransformation.Push;
- if osIgnoreDepthBuffer in ObjectStyle then
- begin
- ARci.gxStates.Disable(stDepthTest);
- DoRender(ARci, True, shouldRenderChildren);
- ARci.gxStates.Enable(stDepthTest);
- end
- else
- DoRender(ARci, True, shouldRenderChildren);
- FEffects.RenderPostEffects(ARci);
- ARci.PipeLineTransformation.Pop;
- end
- else
- begin
- if osIgnoreDepthBuffer in ObjectStyle then
- begin
- ARci.gxStates.Disable(stDepthTest);
- DoRender(ARci, True, shouldRenderChildren);
- ARci.gxStates.Enable(stDepthTest);
- end
- else
- DoRender(ARci, True, shouldRenderChildren);
- end;
- vCurrentRenderingObject := nil;
- end
- else
- begin
- if (osIgnoreDepthBuffer in ObjectStyle) and TgxSceneBuffer(ARci.Buffer).DepthTest then
- begin
- ARci.gxStates.Disable(stDepthTest);
- DoRender(ARci, False, shouldRenderChildren);
- ARci.gxStates.Enable(stDepthTest);
- end
- else
- DoRender(ARci, False, shouldRenderChildren);
- end;
- // Pop Name & Matrix
- if Assigned(master) then
- TgxSceneBuffer(ARci.Buffer).FSelector.CurrentObject := master;
- ARci.PipeLineTransformation.Pop;
- end;
- procedure TgxBaseSceneObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
- begin
- // start rendering self
- if ARenderSelf then
- begin
- if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
- BuildList(ARci)
- else
- ARci.gxStates.CallList(GetHandle(ARci));
- end;
- // start rendering children (if any)
- if ARenderChildren then
- Self.RenderChildren(0, Count - 1, ARci);
- end;
- procedure TgxBaseSceneObject.RenderChildren(firstChildIndex, lastChildIndex: Integer; var rci: TgxRenderContextInfo);
- var
- i: Integer;
- plist: PgxPointerObjectList;
- obj: TgxBaseSceneObject;
- oldSorting: TgxObjectsSorting;
- oldCulling: TgxVisibilityCulling;
- begin
- oldCulling := rci.VisibilityCulling;
- if Self.VisibilityCulling <> vcInherited then
- rci.VisibilityCulling := Self.VisibilityCulling;
- if lastChildIndex = firstChildIndex then
- begin
- obj := TgxBaseSceneObject(FChildren.List^[firstChildIndex]);
- if obj.Visible then
- obj.Render(rci)
- end
- else if lastChildIndex > firstChildIndex then
- begin
- oldSorting := rci.ObjectsSorting;
- if Self.ObjectsSorting <> osInherited then
- rci.ObjectsSorting := Self.ObjectsSorting;
- case rci.ObjectsSorting of
- osNone:
- begin
- plist := FChildren.List;
- for i := firstChildIndex to lastChildIndex do
- begin
- obj := TgxBaseSceneObject(plist^[i]);
- if obj.Visible then
- obj.Render(rci);
- end;
- end;
- osRenderFarthestFirst, osRenderBlendedLast, osRenderNearestFirst:
- begin
- distList.Flush;
- objList.Count := 0;
- distList.GrowthDelta := lastChildIndex + 1; // no reallocations
- objList.GrowthDelta := distList.GrowthDelta;
- // try
- case rci.ObjectsSorting of
- osRenderBlendedLast:
- // render opaque stuff
- for i := firstChildIndex to lastChildIndex do
- begin
- obj := TgxBaseSceneObject(FChildren.List^[i]);
- if obj.Visible then
- begin
- if not obj.Blended then
- obj.Render(rci)
- else
- begin
- objList.Add(obj);
- distList.Add(1 + obj.BarycenterSqrDistanceTo(rci.cameraPosition));
- end;
- end;
- end;
- osRenderFarthestFirst:
- for i := firstChildIndex to lastChildIndex do
- begin
- obj := TgxBaseSceneObject(FChildren.List^[i]);
- if obj.Visible then
- begin
- objList.Add(obj);
- distList.Add(1 + obj.BarycenterSqrDistanceTo(rci.cameraPosition));
- end;
- end;
- osRenderNearestFirst:
- for i := firstChildIndex to lastChildIndex do
- begin
- obj := TgxBaseSceneObject(FChildren.List^[i]);
- if obj.Visible then
- begin
- objList.Add(obj);
- distList.Add(-1 - obj.BarycenterSqrDistanceTo(rci.cameraPosition));
- end;
- end;
- else
- Assert(False);
- end;
- if distList.Count > 0 then
- begin
- if distList.Count > 1 then
- FastQuickSortLists(0, distList.Count - 1, distList, objList);
- plist := objList.List;
- for i := objList.Count - 1 downto 0 do
- TgxBaseSceneObject(plist^[i]).Render(rci);
- end;
- // finally
- // end;
- end;
- else
- Assert(False);
- end;
- rci.ObjectsSorting := oldSorting;
- end;
- rci.VisibilityCulling := oldCulling;
- end;
- procedure TgxBaseSceneObject.NotifyChange(Sender: TObject);
- begin
- if Assigned(FScene) and (not IsUpdating) then
- FScene.NotifyChange(Self);
- end;
- function TgxBaseSceneObject.GetMatrix: PMatrix4f;
- begin
- RebuildMatrix;
- Result := @FLocalMatrix;
- end;
- procedure TgxBaseSceneObject.SetMatrix(const aValue: TMatrix4f);
- begin
- FLocalMatrix := aValue;
- FDirection.DirectVector := VectorNormalize(FLocalMatrix.z);
- FUp.DirectVector := VectorNormalize(FLocalMatrix.y);
- Scale.SetVector(VectorLength(FLocalMatrix.x), VectorLength(FLocalMatrix.y), VectorLength(FLocalMatrix.z), 0);
- FPosition.DirectVector := FLocalMatrix.W;
- TransformationChanged;
- end;
- procedure TgxBaseSceneObject.SetPosition(APosition: TgxCoordinates);
- begin
- FPosition.SetPoint(APosition.DirectX, APosition.DirectY, APosition.DirectZ);
- end;
- procedure TgxBaseSceneObject.SetDirection(AVector: TgxCoordinates);
- begin
- if not VectorIsNull(AVector.DirectVector) then
- FDirection.SetVector(AVector.DirectX, AVector.DirectY, AVector.DirectZ);
- end;
- procedure TgxBaseSceneObject.SetUp(AVector: TgxCoordinates);
- begin
- if not VectorIsNull(AVector.DirectVector) then
- FUp.SetVector(AVector.DirectX, AVector.DirectY, AVector.DirectZ);
- end;
- function TgxBaseSceneObject.GetVisible: Boolean;
- begin
- Result := FVisible;
- end;
- function TgxBaseSceneObject.GetPickable: Boolean;
- begin
- Result := FPickable;
- end;
- procedure TgxBaseSceneObject.SetVisible(aValue: Boolean);
- begin
- if FVisible <> aValue then
- begin
- FVisible := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.SetPickable(aValue: Boolean);
- begin
- if FPickable <> aValue then
- begin
- FPickable := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.SetObjectsSorting(const val: TgxObjectsSorting);
- begin
- if FObjectsSorting <> val then
- begin
- FObjectsSorting := val;
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.SetVisibilityCulling(const val: TgxVisibilityCulling);
- begin
- if FVisibilityCulling <> val then
- begin
- FVisibilityCulling := val;
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseSceneObject.SetBehaviours(const val: TgxBehaviours);
- begin
- Behaviours.Assign(val);
- end;
- function TgxBaseSceneObject.GetBehaviours: TgxBehaviours;
- begin
- if not Assigned(FBehaviours) then
- FBehaviours := TgxBehaviours.Create(Self);
- Result := FBehaviours;
- end;
- procedure TgxBaseSceneObject.SetEffects(const val: TgxEffects);
- begin
- Effects.Assign(val);
- end;
- function TgxBaseSceneObject.GetEffects: TgxEffects;
- begin
- if not Assigned(FEffects) then
- FEffects := TgxEffects.Create(Self);
- Result := FEffects;
- end;
- procedure TgxBaseSceneObject.SetScene(const Value: TgxScene);
- var
- i: Integer;
- begin
- if Value <> FScene then
- begin
- // must be freed, the new scene may be using a non-compatible RC
- if FScene <> nil then
- DestroyHandles;
- FScene := Value;
- // propagate for childs
- if Assigned(FChildren) then
- for i := 0 to FChildren.Count - 1 do
- Children[i].SetScene(FScene);
- end;
- end;
- procedure TgxBaseSceneObject.Translate(tx, ty, tz: Single);
- begin
- FPosition.Translate(AffineVectorMake(tx, ty, tz));
- end;
- function TgxBaseSceneObject.GetAbsoluteAffinePosition: TAffineVector;
- var
- temp: TVector4f;
- begin
- temp := GetAbsolutePosition;
- Result := AffineVectorMake(temp.x, temp.y, temp.z);
- end;
- function TgxBaseSceneObject.GetAbsoluteAffineDirection: TAffineVector;
- var
- temp: TVector4f;
- begin
- temp := GetAbsoluteDirection;
- Result := AffineVectorMake(temp.x, temp.y, temp.z);
- end;
- function TgxBaseSceneObject.GetAbsoluteAffineUp: TAffineVector;
- var
- temp: TVector4f;
- begin
- temp := GetAbsoluteUp;
- Result := AffineVectorMake(temp.x, temp.y, temp.z);
- end;
- procedure TgxBaseSceneObject.SetAbsoluteAffinePosition(const Value: TAffineVector);
- begin
- SetAbsolutePosition(VectorMake(Value, 1));
- end;
- procedure TgxBaseSceneObject.SetAbsoluteAffineUp(const v: TAffineVector);
- begin
- SetAbsoluteUp(VectorMake(v, 1));
- end;
- procedure TgxBaseSceneObject.SetAbsoluteAffineDirection(const v: TAffineVector);
- begin
- SetAbsoluteDirection(VectorMake(v, 1));
- end;
- function TgxBaseSceneObject.AffineLeftVector: TAffineVector;
- begin
- Result := AffineVectorMake(LeftVector);
- end;
- function TgxBaseSceneObject.AffineRight: TAffineVector;
- begin
- Result := AffineVectorMake(Right);
- end;
- function TgxBaseSceneObject.DistanceTo(const pt: TAffineVector): Single;
- begin
- Result := VectorDistance(AbsoluteAffinePosition, pt);
- end;
- function TgxBaseSceneObject.SqrDistanceTo(const pt: TAffineVector): Single;
- begin
- Result := VectorDistance2(AbsoluteAffinePosition, pt);
- end;
- procedure TgxBaseSceneObject.DoOnAddedToParent;
- begin
- if Assigned(FOnAddedToParent) then
- FOnAddedToParent(Self);
- end;
- function TgxBaseSceneObject.GetAbsoluteAffineScale: TAffineVector;
- begin
- Result := AffineVectorMake(GetAbsoluteScale);
- end;
- procedure TgxBaseSceneObject.SetAbsoluteAffineScale(const Value: TAffineVector);
- begin
- SetAbsoluteScale(VectorMake(Value, GetAbsoluteScale.W));
- end;
- // ------------------
- // ------------------ TgxBaseBehaviour ------------------
- // ------------------
- constructor TgxBaseBehaviour.Create(AOwner: TXCollection);
- begin
- inherited Create(AOwner);
- // nothing more, yet
- end;
- destructor TgxBaseBehaviour.Destroy;
- begin
- // nothing more, yet
- inherited Destroy;
- end;
- procedure TgxBaseBehaviour.SetName(const val: string);
- begin
- inherited SetName(val);
- if Assigned(vBehaviourNameChangeEvent) then
- vBehaviourNameChangeEvent(Self);
- end;
- procedure TgxBaseBehaviour.WriteToFiler(writer: TWriter);
- begin
- inherited;
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- // nothing more, yet
- end;
- end;
- procedure TgxBaseBehaviour.ReadFromFiler(reader: TReader);
- begin
- if Owner.ArchiveVersion > 0 then
- inherited;
- with reader do
- begin
- if ReadInteger <> 0 then
- Assert(False);
- // nothing more, yet
- end;
- end;
- function TgxBaseBehaviour.OwnerBaseSceneObject: TgxBaseSceneObject;
- begin
- Result := TgxBaseSceneObject(Owner.Owner);
- end;
- procedure TgxBaseBehaviour.DoProgress(const progressTime: TgxProgressTimes);
- begin
- // does nothing
- end;
- // ------------------
- // ------------------ TgxBehaviours ------------------
- // ------------------
- // Create
- //
- constructor TgxBehaviours.Create(AOwner: TPersistent);
- begin
- Assert(AOwner is TgxBaseSceneObject);
- inherited Create(AOwner);
- end;
- function TgxBehaviours.GetNamePath: string;
- var
- s: string;
- begin
- Result := ClassName;
- if GetOwner = nil then
- Exit;
- s := GetOwner.GetNamePath;
- if s = '' then
- Exit;
- Result := s + '.Behaviours';
- end;
- class function TgxBehaviours.ItemsClass: TXCollectionItemClass;
- begin
- Result := TgxBehaviour;
- end;
- function TgxBehaviours.GetBehaviour(Index: Integer): TgxBehaviour;
- begin
- Result := TgxBehaviour(Items[index]);
- end;
- function TgxBehaviours.CanAdd(aClass: TXCollectionItemClass): Boolean;
- begin
- Result := (not aClass.InheritsFrom(TgxEffect)) and (inherited CanAdd(aClass));
- end;
- procedure TgxBehaviours.DoProgress(const progressTimes: TgxProgressTimes);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TgxBehaviour(Items[i]).DoProgress(progressTimes);
- end;
- // ------------------
- // ------------------ TgxEffect ------------------
- // ------------------
- procedure TgxEffect.WriteToFiler(writer: TWriter);
- begin
- inherited;
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- // nothing more, yet
- end;
- end;
- procedure TgxEffect.ReadFromFiler(reader: TReader);
- begin
- if Owner.ArchiveVersion > 0 then
- inherited;
- with reader do
- begin
- if ReadInteger <> 0 then
- Assert(False);
- // nothing more, yet
- end;
- end;
- procedure TgxEffect.Render(var rci: TgxRenderContextInfo);
- begin
- // nothing here, this implem is just to avoid "abstract error"
- end;
- // ------------------
- // ------------------ TgxEffects ------------------
- // ------------------
- constructor TgxEffects.Create(AOwner: TPersistent);
- begin
- Assert(AOwner is TgxBaseSceneObject);
- inherited Create(AOwner);
- end;
- function TgxEffects.GetNamePath: string;
- var
- s: string;
- begin
- Result := ClassName;
- if GetOwner = nil then
- Exit;
- s := GetOwner.GetNamePath;
- if s = '' then
- Exit;
- Result := s + '.Effects';
- end;
- class function TgxEffects.ItemsClass: TXCollectionItemClass;
- begin
- Result := TgxEffect;
- end;
- function TgxEffects.GetEffect(Index: Integer): TgxEffect;
- begin
- Result := TgxEffect(Items[index]);
- end;
- function TgxEffects.CanAdd(aClass: TXCollectionItemClass): Boolean;
- begin
- Result := (aClass.InheritsFrom(TgxEffect)) and (inherited CanAdd(aClass));
- end;
- procedure TgxEffects.DoProgress(const progressTime: TgxProgressTimes);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TgxEffect(Items[i]).DoProgress(progressTime);
- end;
- procedure TgxEffects.RenderPreEffects(var rci: TgxRenderContextInfo);
- var
- i: Integer;
- effect: TgxEffect;
- begin
- for i := 0 to Count - 1 do
- begin
- effect := TgxEffect(Items[i]);
- if effect is TgxObjectPreEffect then
- effect.Render(rci);
- end;
- end;
- procedure TgxEffects.RenderPostEffects(var rci: TgxRenderContextInfo);
- var
- i: Integer;
- effect: TgxEffect;
- begin
- for i := 0 to Count - 1 do
- begin
- effect := TgxEffect(Items[i]);
- if effect is TgxObjectPostEffect then
- effect.Render(rci)
- else if Assigned(rci.afterRenderEffects) and (effect is TgxObjectAfterEffect) then
- rci.afterRenderEffects.Add(effect);
- end;
- end;
- // ------------------
- // ------------------ TgxCustomSceneObject ------------------
- // ------------------
- constructor TgxCustomSceneObject.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FMaterial := TgxMaterial.Create(Self);
- end;
- destructor TgxCustomSceneObject.Destroy;
- begin
- inherited Destroy;
- FMaterial.Free;
- end;
- procedure TgxCustomSceneObject.Assign(Source: TPersistent);
- begin
- if Source is TgxCustomSceneObject then
- begin
- FMaterial.Assign(TgxCustomSceneObject(Source).FMaterial);
- FHint := TgxCustomSceneObject(Source).FHint;
- end;
- inherited Assign(Source);
- end;
- function TgxCustomSceneObject.Blended: Boolean;
- begin
- Result := Material.Blended;
- end;
- procedure TgxCustomSceneObject.Loaded;
- begin
- inherited;
- FMaterial.Loaded;
- end;
- procedure TgxCustomSceneObject.SetVKMaterial(aValue: TgxMaterial);
- begin
- FMaterial.Assign(aValue);
- NotifyChange(Self);
- end;
- procedure TgxCustomSceneObject.DestroyHandle;
- begin
- inherited;
- FMaterial.DestroyHandles;
- end;
- procedure TgxCustomSceneObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
- begin
- // start rendering self
- if ARenderSelf then
- if ARci.ignoreMaterials then
- if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
- BuildList(ARci)
- else
- ARci.gxStates.CallList(GetHandle(ARci))
- else
- begin
- FMaterial.Apply(ARci);
- repeat
- if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
- BuildList(ARci)
- else
- ARci.gxStates.CallList(GetHandle(ARci));
- until not FMaterial.UnApply(ARci);
- end;
- // start rendering children (if any)
- if ARenderChildren then
- Self.RenderChildren(0, Count - 1, ARci);
- end;
- // ------------------
- // ------------------ TgxSceneRootObject ------------------
- // ------------------
- constructor TgxSceneRootObject.Create(AOwner: TComponent);
- begin
- Assert(AOwner is TgxScene);
- inherited Create(AOwner);
- ObjectStyle := ObjectStyle + [osDirectDraw];
- FScene := TgxScene(AOwner);
- end;
- // ------------------
- // ------------------ TgxCamera ------------------
- // ------------------
- constructor TgxCamera.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FFocalLength := 50;
- FDepthOfView := 100;
- FNearPlaneBias := 1;
- FDirection.Initialize(VectorMake(0, 0, -1, 0));
- FCameraStyle := csPerspective;
- FSceneScale := 1;
- FDesign := False;
- FFOVY := -1;
- FKeepFOVMode := ckmHorizontalFOV;
- end;
- destructor TgxCamera.Destroy;
- begin
- TargetObject := nil;
- inherited;
- end;
- procedure TgxCamera.Assign(Source: TPersistent);
- var
- cam: TgxCamera;
- dir: TVector4f;
- begin
- if Assigned(Source) then
- begin
- inherited Assign(Source);
- if Source is TgxCamera then
- begin
- cam := TgxCamera(Source);
- SetDepthOfView(cam.DepthOfView);
- SetFocalLength(cam.FocalLength);
- SetCameraStyle(cam.CameraStyle);
- SetSceneScale(cam.SceneScale);
- SetNearPlaneBias(cam.NearPlaneBias);
- SetScene(cam.Scene);
- SetKeepFOVMode(cam.FKeepFOVMode);
- if Parent <> nil then
- begin
- SetTargetObject(cam.TargetObject);
- end
- else // Design camera
- begin
- Position.AsVector := cam.AbsolutePosition;
- if Assigned(cam.TargetObject) then
- begin
- VectorSubtract(cam.TargetObject.AbsolutePosition, AbsolutePosition, dir);
- NormalizeVector(dir);
- Direction.AsVector := dir;
- end;
- end;
- end;
- end;
- end;
- function TgxCamera.AbsoluteVectorToTarget: TVector4f;
- begin
- if TargetObject <> nil then
- begin
- VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition, Result);
- NormalizeVector(Result);
- end
- else
- Result := AbsoluteDirection;
- end;
- function TgxCamera.AbsoluteRightVectorToTarget: TVector4f;
- begin
- if TargetObject <> nil then
- begin
- VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition, Result);
- Result := VectorCrossProduct(Result, AbsoluteUp);
- NormalizeVector(Result);
- end
- else
- Result := AbsoluteRight;
- end;
- function TgxCamera.AbsoluteUpVectorToTarget: TVector4f;
- begin
- if TargetObject <> nil then
- Result := VectorCrossProduct(AbsoluteRightVectorToTarget, AbsoluteVectorToTarget)
- else
- Result := AbsoluteUp;
- end;
- // Apply
- //
- procedure TgxCamera.Apply;
- var
- v, d, v2: TVector4f;
- absPos: TVector4f;
- LM, mat: TMatrix4f;
- begin
- if Assigned(FDeferredApply) then
- FDeferredApply(Self)
- else
- begin
- if Assigned(FTargetObject) then
- begin
- v := TargetObject.AbsolutePosition;
- absPos := AbsolutePosition;
- VectorSubtract(v, absPos, d);
- NormalizeVector(d);
- FLastDirection := d;
- LM := CreateLookAtMatrix(absPos, v, Up.AsVector);
- end
- else
- begin
- if Assigned(Parent) then
- mat := Parent.AbsoluteMatrix
- else
- mat := IdentityHmgMatrix;
- absPos := AbsolutePosition;
- v := VectorTransform(Direction.AsVector, mat);
- FLastDirection := v;
- d := VectorTransform(Up.AsVector, mat);
- v2 := VectorAdd(absPos, v);
- LM := CreateLookAtMatrix(absPos, v2, d);
- end;
- with CurrentContext.PipeLineTransformation do
- SetViewMatrix(MatrixMultiply(LM, ViewMatrix^));
- ClearStructureChanged;
- end;
- end;
- procedure TgxCamera.ApplyPerspective(const AViewport: TRectangle; AWidth, AHeight: Integer; ADPI: Integer);
- var
- vLeft, vRight, vBottom, vTop, vFar: Single;
- MaxDim, ratio, f: Double;
- xmax, ymax: Double;
- mat: TMatrix4f;
- const
- cEpsilon: Single = 1E-4;
- function IsPerspective(CamStyle: TgxCameraStyle): Boolean;
- begin
- Result := CamStyle in [csPerspective, csInfinitePerspective, csPerspectiveKeepFOV];
- end;
- begin
- if (AWidth <= 0) or (AHeight <= 0) then
- Exit;
- if CameraStyle = csOrtho2D then
- begin
- vLeft := 0;
- vRight := AWidth;
- vBottom := 0;
- vTop := AHeight;
- FNearPlane := -1;
- vFar := 1;
- mat := CreateOrthoMatrix(vLeft, vRight, vBottom, vTop, FNearPlane, vFar);
- with CurrentContext.PipeLineTransformation do
- SetProjectionMatrix(MatrixMultiply(mat, ProjectionMatrix^));
- FViewPortRadius := VectorLength(AWidth, AHeight) / 2;
- end
- else if CameraStyle = csCustom then
- begin
- FViewPortRadius := VectorLength(AWidth, AHeight) / 2;
- if Assigned(FOnCustomPerspective) then
- FOnCustomPerspective(AViewport, AWidth, AHeight, ADPI, FViewPortRadius);
- end
- else
- begin
- // determine biggest dimension and resolution (height or width)
- MaxDim := AWidth;
- if AHeight > MaxDim then
- MaxDim := AHeight;
- // calculate near plane distance and extensions;
- // Scene ratio is determined by the window ratio. The viewport is just a
- // specific part of the entire window and has therefore no influence on the
- // scene ratio. What we need to know, though, is the ratio between the window
- // borders (left, top, right and bottom) and the viewport borders.
- // Note: viewport.top is actually bottom, because the window (and viewport) origin
- // in OGL is the lower left corner
- if IsPerspective(CameraStyle) then
- f := FNearPlaneBias / (AWidth * FSceneScale)
- else
- f := 100 * FNearPlaneBias / (FocalLength * AWidth * FSceneScale);
- // calculate window/viewport ratio for right extent
- ratio := (2 * AViewport.width + 2 * AViewport.Left - AWidth) * f;
- // calculate aspect ratio correct right value of the view frustum and take
- // the window/viewport ratio also into account
- vRight := ratio * AWidth / (2 * MaxDim);
- // the same goes here for the other three extents
- // left extent:
- ratio := (AWidth - 2 * AViewport.Left) * f;
- vLeft := -ratio * AWidth / (2 * MaxDim);
- if IsPerspective(CameraStyle) then
- f := FNearPlaneBias / (AHeight * FSceneScale)
- else
- f := 100 * FNearPlaneBias / (FocalLength * AHeight * FSceneScale);
- // top extent (keep in mind the origin is left lower corner):
- ratio := (2 * AViewport.height + 2 * AViewport.Top - AHeight) * f;
- vTop := ratio * AHeight / (2 * MaxDim);
- // bottom extent:
- ratio := (AHeight - 2 * AViewport.Top) * f;
- vBottom := -ratio * AHeight / (2 * MaxDim);
- FNearPlane := FFocalLength * 2 * ADPI / (25.4 * MaxDim) * FNearPlaneBias;
- vFar := FNearPlane + FDepthOfView;
- // finally create view frustum (perspective or orthogonal)
- case CameraStyle of
- csPerspective:
- begin
- mat := CreateMatrixFromFrustum(vLeft, vRight, vBottom, vTop, FNearPlane, vFar);
- end;
- csPerspectiveKeepFOV:
- begin
- if FFOVY < 0 then // Need Update FOV
- begin
- FFOVY := ArcTan2(vTop - vBottom, 2 * FNearPlane) * 2;
- FFOVX := ArcTan2(vRight - vLeft, 2 * FNearPlane) * 2;
- end;
- case FKeepFOVMode of
- ckmVerticalFOV:
- begin
- ymax := FNearPlane * Tan(FFOVY / 2);
- xmax := ymax * AWidth / AHeight;
- end;
- ckmHorizontalFOV:
- begin
- xmax := FNearPlane * Tan(FFOVX / 2);
- ymax := xmax * AHeight / AWidth;
- end;
- else
- begin
- xmax := 0;
- ymax := 0;
- Assert(False, 'Unknown keep camera angle mode');
- end;
- end;
- mat := CreateMatrixFromFrustum(-xmax, xmax, -ymax, ymax, FNearPlane, vFar);
- end;
- csInfinitePerspective:
- begin
- mat := IdentityHmgMatrix;
- mat.x.x := 2 * FNearPlane / (vRight - vLeft);
- mat.y.y := 2 * FNearPlane / (vTop - vBottom);
- mat.z.x := (vRight + vLeft) / (vRight - vLeft);
- mat.z.y := (vTop + vBottom) / (vTop - vBottom);
- mat.z.z := cEpsilon - 1;
- mat.z.W := -1;
- mat.W.z := FNearPlane * (cEpsilon - 2);
- mat.W.W := 0;
- end;
- csOrthogonal:
- begin
- mat := CreateOrthoMatrix(vLeft, vRight, vBottom, vTop, FNearPlane, vFar);
- end;
- else
- Assert(False);
- end;
- with CurrentContext.PipeLineTransformation do
- SetProjectionMatrix(MatrixMultiply(mat, ProjectionMatrix^));
- FViewPortRadius := VectorLength(vRight, vTop) / FNearPlane
- end;
- end;
- // ------------------------------------------------------------------------------
- procedure TgxCamera.AutoLeveling(Factor: Single);
- var
- rightVector, rotAxis: TVector4f;
- angle: Single;
- begin
- angle := RadianToDeg(ArcCosine(VectorDotProduct(FUp.AsVector, YVector)));
- rotAxis := VectorCrossProduct(YHmgVector, FUp.AsVector);
- if (angle > 1) and (VectorLength(rotAxis) > 0) then
- begin
- rightVector := VectorCrossProduct(FDirection.AsVector, FUp.AsVector);
- FUp.Rotate(AffineVectorMake(rotAxis), angle / (10 * Factor));
- FUp.Normalize;
- // adjust local coordinates
- FDirection.DirectVector := VectorCrossProduct(FUp.AsVector, rightVector);
- FRotation.z := -RadToDeg(ArcTan2(rightVector.y, VectorLength(rightVector.x, rightVector.z)));
- end;
- end;
- // ------------------------------------------------------------------------------
- procedure TgxCamera.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- if (Operation = opRemove) and (AComponent = FTargetObject) then
- TargetObject := nil;
- inherited;
- end;
- procedure TgxCamera.SetTargetObject(const val: TgxBaseSceneObject);
- begin
- if (FTargetObject <> val) then
- begin
- if Assigned(FTargetObject) then
- FTargetObject.RemoveFreeNotification(Self);
- FTargetObject := val;
- if Assigned(FTargetObject) then
- FTargetObject.FreeNotification(Self);
- if not(csLoading in ComponentState) then
- TransformationChanged;
- end;
- end;
- procedure TgxCamera.Reset(aSceneBuffer: TgxSceneBuffer);
- var
- Extent: Single;
- begin
- FRotation.z := 0;
- FFocalLength := 50;
- with aSceneBuffer do
- begin
- ApplyPerspective(FViewPort, FViewPort.width, FViewPort.height, FRenderDPI);
- FUp.DirectVector := YHmgVector;
- if FViewPort.height < FViewPort.width then
- Extent := FViewPort.height * 0.25
- else
- Extent := FViewPort.width * 0.25;
- end;
- FPosition.SetPoint(0, 0, FNearPlane * Extent);
- FDirection.SetVector(0, 0, -1, 0);
- TransformationChanged;
- end;
- procedure TgxCamera.ZoomAll(aSceneBuffer: TgxSceneBuffer);
- var
- Extent: Single;
- begin
- with aSceneBuffer do
- begin
- if FViewPort.height < FViewPort.width then
- Extent := FViewPort.height * 0.25
- else
- Extent := FViewPort.width * 0.25;
- FPosition.DirectVector := NullHmgPoint;
- Move(-FNearPlane * Extent);
- // let the camera look at the scene center
- FDirection.SetVector(-FPosition.x, -FPosition.y, -FPosition.z, 0);
- end;
- end;
- procedure TgxCamera.RotateObject(obj: TgxBaseSceneObject; pitchDelta, turnDelta: Single; rollDelta: Single = 0);
- var
- resMat: TMatrix4f;
- vDir, vUp, vRight: TVector4f;
- v: TAffineVector;
- position1: TVector4f;
- Scale1: TVector4f;
- begin
- // First we need to compute the actual camera's vectors, which may not be
- // directly available if we're in "targeting" mode
- vUp := AbsoluteUp;
- if TargetObject <> nil then
- begin
- vDir := AbsoluteVectorToTarget;
- vRight := VectorCrossProduct(vDir, vUp);
- vUp := VectorCrossProduct(vRight, vDir);
- end
- else
- begin
- vDir := AbsoluteDirection;
- vRight := VectorCrossProduct(vDir, vUp);
- end;
- // save scale & position info
- Scale1 := obj.Scale.AsVector;
- position1 := obj.Position.AsVector;
- resMat := obj.Matrix^;
- // get rid of scaling & location info
- NormalizeMatrix(resMat);
- // Now we build rotation matrices and use them to rotate the obj
- if rollDelta <> 0 then
- begin
- SetVector(v, obj.AbsoluteToLocal(vDir));
- resMat := MatrixMultiply(CreateRotationMatrix(v, DegToRadian(rollDelta)), resMat);
- end;
- if turnDelta <> 0 then
- begin
- SetVector(v, obj.AbsoluteToLocal(vUp));
- resMat := MatrixMultiply(CreateRotationMatrix(v, DegToRadian(turnDelta)), resMat);
- end;
- if pitchDelta <> 0 then
- begin
- SetVector(v, obj.AbsoluteToLocal(vRight));
- resMat := MatrixMultiply(CreateRotationMatrix(v, DegToRadian(pitchDelta)), resMat);
- end;
- obj.SetMatrix(resMat);
- // restore scaling & rotation info
- obj.Scale.AsVector := Scale1;
- obj.Position.AsVector := position1;
- end;
- procedure TgxCamera.RotateTarget(pitchDelta, turnDelta: Single; rollDelta: Single = 0);
- begin
- if Assigned(FTargetObject) then
- RotateObject(FTargetObject, pitchDelta, turnDelta, rollDelta)
- end;
- procedure TgxCamera.MoveAroundTarget(pitchDelta, turnDelta: Single);
- begin
- MoveObjectAround(FTargetObject, pitchDelta, turnDelta);
- end;
- procedure TgxCamera.MoveAllAroundTarget(pitchDelta, turnDelta: Single);
- begin
- MoveObjectAllAround(FTargetObject, pitchDelta, turnDelta);
- end;
- procedure TgxCamera.MoveInEyeSpace(forwardDistance, rightDistance, upDistance: Single);
- var
- trVector: TVector4f;
- begin
- trVector := AbsoluteEyeSpaceVector(forwardDistance, rightDistance, upDistance);
- if Assigned(Parent) then
- Position.Translate(Parent.AbsoluteToLocal(trVector))
- else
- Position.Translate(trVector);
- end;
- procedure TgxCamera.MoveTargetInEyeSpace(forwardDistance, rightDistance, upDistance: Single);
- var
- trVector: TVector4f;
- begin
- if TargetObject <> nil then
- begin
- trVector := AbsoluteEyeSpaceVector(forwardDistance, rightDistance, upDistance);
- TargetObject.Position.Translate(TargetObject.Parent.AbsoluteToLocal(trVector));
- end;
- end;
- function TgxCamera.AbsoluteEyeSpaceVector(forwardDistance, rightDistance, upDistance: Single): TVector4f;
- begin
- Result := NullHmgVector;
- if forwardDistance <> 0 then
- CombineVector(Result, AbsoluteVectorToTarget, forwardDistance);
- if rightDistance <> 0 then
- CombineVector(Result, AbsoluteRightVectorToTarget, rightDistance);
- if upDistance <> 0 then
- CombineVector(Result, AbsoluteUpVectorToTarget, upDistance);
- end;
- procedure TgxCamera.AdjustDistanceToTarget(distanceRatio: Single);
- var
- vect: TVector4f;
- begin
- if Assigned(FTargetObject) then
- begin
- // calculate vector from target to camera in absolute coordinates
- vect := VectorSubtract(AbsolutePosition, TargetObject.AbsolutePosition);
- // ratio -> translation vector
- ScaleVector(vect, -(1 - distanceRatio));
- AddVector(vect, AbsolutePosition);
- if Assigned(Parent) then
- vect := Parent.AbsoluteToLocal(vect);
- Position.AsVector := vect;
- end;
- end;
- function TgxCamera.DistanceToTarget: Single;
- var
- vect: TVector4f;
- begin
- if Assigned(FTargetObject) then
- begin
- vect := VectorSubtract(AbsolutePosition, TargetObject.AbsolutePosition);
- Result := VectorLength(vect);
- end
- else
- Result := 1;
- end;
- function TgxCamera.ScreenDeltaToVector(deltaX, deltaY: Integer; ratio: Single; const planeNormal: TVector4f): TVector4f;
- var
- screenY, screenX: TVector4f;
- screenYoutOfPlaneComponent: Single;
- begin
- // calculate projection of direction vector on the plane
- if Assigned(FTargetObject) then
- screenY := VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition)
- else
- screenY := Direction.AsVector;
- screenYoutOfPlaneComponent := VectorDotProduct(screenY, planeNormal);
- screenY := VectorCombine(screenY, planeNormal, 1, -screenYoutOfPlaneComponent);
- NormalizeVector(screenY);
- // calc the screenX vector
- screenX := VectorCrossProduct(screenY, planeNormal);
- // and here, we're done
- Result := VectorCombine(screenX, screenY, deltaX * ratio, deltaY * ratio);
- end;
- function TgxCamera.ScreenDeltaToVectorXY(deltaX, deltaY: Integer; ratio: Single): TVector4f;
- var
- screenY: TVector4f;
- dxr, dyr, d: Single;
- begin
- // calculate projection of direction vector on the plane
- if Assigned(FTargetObject) then
- screenY := VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition)
- else
- screenY := Direction.AsVector;
- d := VectorLength(screenY.x, screenY.y);
- if d <= 1E-10 then
- d := ratio
- else
- d := ratio / d;
- // and here, we're done
- dxr := deltaX * d;
- dyr := deltaY * d;
- Result.x := screenY.y * dxr + screenY.x * dyr;
- Result.y := screenY.y * dyr - screenY.x * dxr;
- Result.z := 0;
- Result.W := 0;
- end;
- function TgxCamera.ScreenDeltaToVectorXZ(deltaX, deltaY: Integer; ratio: Single): TVector4f;
- var
- screenY: TVector4f;
- d, dxr, dzr: Single;
- begin
- // calculate the projection of direction vector on the plane
- if Assigned(FTargetObject) then
- screenY := VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition)
- else
- screenY := Direction.AsVector;
- d := VectorLength(screenY.x, screenY.z);
- if d <= 1E-10 then
- d := ratio
- else
- d := ratio / d;
- dxr := deltaX * d;
- dzr := deltaY * d;
- Result.x := -screenY.z * dxr + screenY.x * dzr;
- Result.y := 0;
- Result.z := screenY.z * dzr + screenY.x * dxr;
- Result.W := 0;
- end;
- function TgxCamera.ScreenDeltaToVectorYZ(deltaX, deltaY: Integer; ratio: Single): TVector4f;
- var
- screenY: TVector4f;
- d, dyr, dzr: Single;
- begin
- // calculate the projection of direction vector on the plane
- if Assigned(FTargetObject) then
- screenY := VectorSubtract(TargetObject.AbsolutePosition, AbsolutePosition)
- else
- screenY := Direction.AsVector;
- d := VectorLength(screenY.y, screenY.z);
- if d <= 1E-10 then
- d := ratio
- else
- d := ratio / d;
- dyr := deltaX * d;
- dzr := deltaY * d;
- Result.x := 0;
- Result.y := screenY.z * dyr + screenY.y * dzr;
- Result.z := screenY.z * dzr - screenY.y * dyr;
- Result.W := 0;
- end;
- function TgxCamera.PointInFront(const point: TVector4f): Boolean;
- begin
- Result := PointIsInHalfSpace(point, AbsolutePosition, AbsoluteDirection);
- end;
- procedure TgxCamera.SetDepthOfView(aValue: Single);
- begin
- if FDepthOfView <> aValue then
- begin
- FDepthOfView := aValue;
- FFOVY := -1;
- if not(csLoading in ComponentState) then
- TransformationChanged;
- end;
- end;
- procedure TgxCamera.SetFocalLength(aValue: Single);
- begin
- if aValue <= 0 then
- aValue := 1;
- if FFocalLength <> aValue then
- begin
- FFocalLength := aValue;
- FFOVY := -1;
- if not(csLoading in ComponentState) then
- TransformationChanged;
- end;
- end;
- function TgxCamera.GetFieldOfView(const AViewportDimension: Single): Single;
- begin
- if FFocalLength = 0 then
- Result := 0
- else
- Result := RadToDeg(2 * ArcTan2(AViewportDimension * 0.5, FFocalLength));
- end;
- procedure TgxCamera.SetFieldOfView(const AFieldOfView, AViewportDimension: Single);
- begin
- FocalLength := AViewportDimension / (2 * Tan(DegToRadian(AFieldOfView / 2)));
- end;
- procedure TgxCamera.SetCameraStyle(const val: TgxCameraStyle);
- begin
- if FCameraStyle <> val then
- begin
- FCameraStyle := val;
- FFOVY := -1;
- NotifyChange(Self);
- end;
- end;
- procedure TgxCamera.SetKeepFOVMode(const val: TgxCameraKeepFOVMode);
- begin
- if FKeepFOVMode <> val then
- begin
- FKeepFOVMode := val;
- FFOVY := -1;
- if FCameraStyle = csPerspectiveKeepFOV then
- NotifyChange(Self);
- end;
- end;
- procedure TgxCamera.SetSceneScale(Value: Single);
- begin
- if Value = 0 then
- Value := 1;
- if FSceneScale <> Value then
- begin
- FSceneScale := Value;
- FFOVY := -1;
- NotifyChange(Self);
- end;
- end;
- function TgxCamera.StoreSceneScale: Boolean;
- begin
- Result := (FSceneScale <> 1);
- end;
- procedure TgxCamera.SetNearPlaneBias(Value: Single);
- begin
- if Value <= 0 then
- Value := 1;
- if FNearPlaneBias <> Value then
- begin
- FNearPlaneBias := Value;
- FFOVY := -1;
- NotifyChange(Self);
- end;
- end;
- function TgxCamera.StoreNearPlaneBias: Boolean;
- begin
- Result := (FNearPlaneBias <> 1);
- end;
- procedure TgxCamera.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
- begin
- if ARenderChildren and (Count > 0) then
- Self.RenderChildren(0, Count - 1, ARci);
- end;
- function TgxCamera.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
- intersectNormal: PVector4f = nil): Boolean;
- begin
- Result := False;
- end;
- // ------------------
- // ------------------ TgxImmaterialSceneObject ------------------
- // ------------------
- procedure TgxImmaterialSceneObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
- begin
- // start rendering self
- if ARenderSelf then
- begin
- if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
- BuildList(ARci)
- else
- ARci.gxStates.CallList(GetHandle(ARci));
- end;
- // start rendering children (if any)
- if ARenderChildren then
- Self.RenderChildren(0, Count - 1, ARci);
- end;
- // ------------------
- // ------------------ TgxCameraInvariantObject ------------------
- // ------------------
- constructor TgxCameraInvariantObject.Create(AOwner: TComponent);
- begin
- inherited;
- FCamInvarianceMode := cimNone;
- end;
- procedure TgxCameraInvariantObject.Assign(Source: TPersistent);
- begin
- if Source is TgxCameraInvariantObject then
- begin
- FCamInvarianceMode := TgxCameraInvariantObject(Source).FCamInvarianceMode;
- end;
- inherited Assign(Source);
- end;
- procedure TgxCameraInvariantObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
- begin
- if CamInvarianceMode <> cimNone then
- with ARci.PipeLineTransformation do
- begin
- Push;
- // try
- // prepare
- case CamInvarianceMode of
- cimPosition:
- begin
- SetViewMatrix(MatrixMultiply(CreateTranslationMatrix(ARci.cameraPosition),
- ARci.PipeLineTransformation.ViewMatrix^));
- end;
- cimOrientation:
- begin
- // makes the coordinates system more 'intuitive' (Z+ forward)
- SetViewMatrix(CreateScaleMatrix(Vector3fMake(1, -1, -1)))
- end;
- else
- Assert(False);
- end;
- // Apply local transform
- SetModelMatrix(LocalMatrix^);
- if ARenderSelf then
- begin
- if (osDirectDraw in ObjectStyle) or ARci.amalgamating then
- BuildList(ARci)
- else
- ARci.gxStates.CallList(GetHandle(ARci));
- end;
- if ARenderChildren then
- Self.RenderChildren(0, Count - 1, ARci);
- // finally
- Pop;
- // end;
- end
- else
- inherited;
- end;
- procedure TgxCameraInvariantObject.SetCamInvarianceMode(const val: TgxCameraInvarianceMode);
- begin
- if FCamInvarianceMode <> val then
- begin
- FCamInvarianceMode := val;
- NotifyChange(Self);
- end;
- end;
- // ------------------
- // ------------------ TxDirectOpenGL ------------------
- // ------------------
- constructor TgxDirectOpenGL.Create(AOwner: TComponent);
- begin
- inherited;
- ObjectStyle := ObjectStyle + [osDirectDraw];
- FBlend := False;
- end;
- procedure TgxDirectOpenGL.Assign(Source: TPersistent);
- begin
- if Source is TgxDirectOpenGL then
- begin
- UseBuildList := TgxDirectOpenGL(Source).UseBuildList;
- FOnRender := TgxDirectOpenGL(Source).FOnRender;
- FBlend := TgxDirectOpenGL(Source).Blend;
- end;
- inherited Assign(Source);
- end;
- procedure TgxDirectOpenGL.BuildList(var rci: TgxRenderContextInfo);
- begin
- if Assigned(FOnRender) then
- begin
- xglMapTexCoordToMain; // single texturing by default
- OnRender(Self, rci);
- end;
- end;
- function TgxDirectOpenGL.AxisAlignedDimensionsUnscaled: TVector4f;
- begin
- Result := NullHmgPoint;
- end;
- procedure TgxDirectOpenGL.SetUseBuildList(const val: Boolean);
- begin
- if val <> FUseBuildList then
- begin
- FUseBuildList := val;
- if val then
- ObjectStyle := ObjectStyle - [osDirectDraw]
- else
- ObjectStyle := ObjectStyle + [osDirectDraw];
- end;
- end;
- function TgxDirectOpenGL.Blended: Boolean;
- begin
- Result := FBlend;
- end;
- procedure TgxDirectOpenGL.SetBlend(const val: Boolean);
- begin
- if val <> FBlend then
- begin
- FBlend := val;
- StructureChanged;
- end;
- end;
- // ------------------
- // ------------------ TgxRenderPoint ------------------
- // ------------------
- constructor TgxRenderPoint.Create(AOwner: TComponent);
- begin
- inherited;
- ObjectStyle := ObjectStyle + [osDirectDraw];
- end;
- destructor TgxRenderPoint.Destroy;
- begin
- Clear;
- inherited;
- end;
- procedure TgxRenderPoint.BuildList(var rci: TgxRenderContextInfo);
- var
- i: Integer;
- begin
- for i := 0 to High(FCallBacks) do
- FCallBacks[i](Self, rci);
- end;
- procedure TgxRenderPoint.RegisterCallBack(renderEvent: TDirectRenderEvent; renderPointFreed: TNotifyEvent);
- var
- n: Integer;
- begin
- n := Length(FCallBacks);
- SetLength(FCallBacks, n + 1);
- SetLength(FFreeCallBacks, n + 1);
- FCallBacks[n] := renderEvent;
- FFreeCallBacks[n] := renderPointFreed;
- end;
- procedure TgxRenderPoint.UnRegisterCallBack(renderEvent: TDirectRenderEvent);
- type
- TEventContainer = record
- event: TDirectRenderEvent;
- end;
- var
- i, j, n: Integer;
- refContainer, listContainer: TEventContainer;
- begin
- refContainer.event := renderEvent;
- n := Length(FCallBacks);
- for i := 0 to n - 1 do
- begin
- listContainer.event := FCallBacks[i];
- if CompareMem(@listContainer, @refContainer, SizeOf(TEventContainer)) then
- begin
- for j := i + 1 to n - 1 do
- begin
- FCallBacks[j - 1] := FCallBacks[j];
- FFreeCallBacks[j - 1] := FFreeCallBacks[j];
- end;
- SetLength(FCallBacks, n - 1);
- SetLength(FFreeCallBacks, n - 1);
- Break;
- end;
- end;
- end;
- procedure TgxRenderPoint.Clear;
- begin
- while Length(FCallBacks) > 0 do
- begin
- FFreeCallBacks[High(FCallBacks)](Self);
- SetLength(FCallBacks, Length(FCallBacks) - 1);
- end;
- end;
- // ------------------
- // ------------------ TgxProxyObject ------------------
- // ------------------
- constructor TgxProxyObject.Create(AOwner: TComponent);
- begin
- inherited;
- FProxyOptions := cDefaultProxyOptions;
- end;
- destructor TgxProxyObject.Destroy;
- begin
- SetMasterObject(nil);
- inherited;
- end;
- procedure TgxProxyObject.Assign(Source: TPersistent);
- begin
- if Source is TgxProxyObject then
- begin
- SetMasterObject(TgxProxyObject(Source).MasterObject);
- end;
- inherited Assign(Source);
- end;
- procedure TgxProxyObject.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
- var
- gotMaster, masterGotEffects, oldProxySubObject: Boolean;
- begin
- if FRendering then
- Exit;
- FRendering := True;
- try
- gotMaster := Assigned(FMasterObject);
- masterGotEffects := gotMaster and (pooEffects in FProxyOptions) and (FMasterObject.Effects.Count > 0);
- if gotMaster then
- begin
- if pooObjects in FProxyOptions then
- begin
- oldProxySubObject := ARci.proxySubObject;
- ARci.proxySubObject := True;
- if pooTransformation in FProxyOptions then
- with ARci.PipeLineTransformation do
- SetModelMatrix(MatrixMultiply(FMasterObject.Matrix^, ModelMatrix^));
- FMasterObject.DoRender(ARci, ARenderSelf, (FMasterObject.Count > 0));
- ARci.proxySubObject := oldProxySubObject;
- end;
- end;
- // now render self stuff (our children, our effects, etc.)
- if ARenderChildren and (Count > 0) then
- Self.RenderChildren(0, Count - 1, ARci);
- if masterGotEffects then
- FMasterObject.Effects.RenderPostEffects(ARci);
- finally
- FRendering := False;
- end;
- ClearStructureChanged;
- end;
- function TgxProxyObject.AxisAlignedDimensions: TVector4f;
- begin
- If Assigned(FMasterObject) then
- begin
- Result := FMasterObject.AxisAlignedDimensionsUnscaled;
- If (pooTransformation in ProxyOptions) then
- ScaleVector(Result, FMasterObject.Scale.AsVector)
- else
- ScaleVector(Result, Scale.AsVector);
- end
- else
- Result := inherited AxisAlignedDimensions;
- end;
- function TgxProxyObject.AxisAlignedDimensionsUnscaled: TVector4f;
- begin
- if Assigned(FMasterObject) then
- begin
- Result := FMasterObject.AxisAlignedDimensionsUnscaled;
- end
- else
- Result := inherited AxisAlignedDimensionsUnscaled;
- end;
- function TgxProxyObject.BarycenterAbsolutePosition: TVector4f;
- var
- lAdjustVector: TVector4f;
- begin
- if Assigned(FMasterObject) then
- begin
- // Not entirely correct, but better than nothing...
- lAdjustVector := VectorSubtract(FMasterObject.BarycenterAbsolutePosition, FMasterObject.AbsolutePosition);
- Position.AsVector := VectorAdd(Position.AsVector, lAdjustVector);
- Result := AbsolutePosition;
- Position.AsVector := VectorSubtract(Position.AsVector, lAdjustVector);
- end
- else
- Result := inherited BarycenterAbsolutePosition;
- end;
- procedure TgxProxyObject.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- if (Operation = opRemove) and (AComponent = FMasterObject) then
- MasterObject := nil;
- inherited;
- end;
- procedure TgxProxyObject.SetMasterObject(const val: TgxBaseSceneObject);
- begin
- if FMasterObject <> val then
- begin
- if Assigned(FMasterObject) then
- FMasterObject.RemoveFreeNotification(Self);
- FMasterObject := val;
- if Assigned(FMasterObject) then
- FMasterObject.FreeNotification(Self);
- StructureChanged;
- end;
- end;
- procedure TgxProxyObject.SetProxyOptions(const val: TgxProxyObjectOptions);
- begin
- if FProxyOptions <> val then
- begin
- FProxyOptions := val;
- StructureChanged;
- end;
- end;
- function TgxProxyObject.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
- intersectNormal: PVector4f = nil): Boolean;
- var
- localRayStart, localRayVector: TVector4f;
- begin
- if Assigned(MasterObject) then
- begin
- SetVector(localRayStart, AbsoluteToLocal(rayStart));
- SetVector(localRayStart, MasterObject.LocalToAbsolute(localRayStart));
- SetVector(localRayVector, AbsoluteToLocal(rayVector));
- SetVector(localRayVector, MasterObject.LocalToAbsolute(localRayVector));
- NormalizeVector(localRayVector);
- Result := MasterObject.RayCastIntersect(localRayStart, localRayVector, intersectPoint, intersectNormal);
- if Result then
- begin
- if Assigned(intersectPoint) then
- begin
- SetVector(intersectPoint^, MasterObject.AbsoluteToLocal(intersectPoint^));
- SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
- end;
- if Assigned(intersectNormal) then
- begin
- SetVector(intersectNormal^, MasterObject.AbsoluteToLocal(intersectNormal^));
- SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
- end;
- end;
- end
- else
- Result := False;
- end;
- function TgxProxyObject.GenerateSilhouette(const silhouetteParameters: TgxSilhouetteParameters): TgxSilhouette;
- begin
- if Assigned(MasterObject) then
- Result := MasterObject.GenerateSilhouette(silhouetteParameters)
- else
- Result := nil;
- end;
- // ------------------
- // ------------------ TxLightSource ------------------
- // ------------------
- constructor TgxLightSource.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FListHandle := nil;
- FShining := True;
- FSpotDirection := TgxCoordinates.CreateInitialized(Self, VectorMake(0, 0, -1, 0), csVector);
- FConstAttenuation := 1;
- FLinearAttenuation := 0;
- FQuadraticAttenuation := 0;
- FSpotCutOff := 180;
- FSpotExponent := 0;
- FLightStyle := lsSpot;
- FAmbient := TgxColor.Create(Self);
- FDiffuse := TgxColor.Create(Self);
- FDiffuse.Initialize(clrWhite);
- FSpecular := TgxColor.Create(Self);
- end;
- destructor TgxLightSource.Destroy;
- begin
- FSpotDirection.Free;
- FAmbient.Free;
- FDiffuse.Free;
- FSpecular.Free;
- inherited Destroy;
- end;
- procedure TgxLightSource.DoRender(var ARci: TgxRenderContextInfo; ARenderSelf, ARenderChildren: Boolean);
- begin
- if ARenderChildren and Assigned(FChildren) then
- Self.RenderChildren(0, Count - 1, ARci);
- end;
- function TgxLightSource.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
- intersectNormal: PVector4f = nil): Boolean;
- begin
- Result := False;
- end;
- procedure TgxLightSource.CoordinateChanged(Sender: TgxCustomCoordinates);
- begin
- inherited;
- if Sender = FSpotDirection then
- TransformationChanged;
- end;
- function TgxLightSource.GenerateSilhouette(const SilhouetteParameters: TgxSilhouetteParameters): TgxSilhouette;
- begin
- Result := nil;
- end;
- procedure TgxLightSource.SetShining(aValue: Boolean);
- begin
- if aValue <> FShining then
- begin
- FShining := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxLightSource.SetSpotDirection(AVector: TgxCoordinates);
- begin
- FSpotDirection.DirectVector := AVector.AsVector;
- FSpotDirection.W := 0;
- NotifyChange(Self);
- end;
- procedure TgxLightSource.SetSpotExponent(aValue: Single);
- begin
- if FSpotExponent <> aValue then
- begin
- FSpotExponent := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxLightSource.SetSpotCutOff(const val: Single);
- begin
- if FSpotCutOff <> val then
- begin
- if ((val >= 0) and (val <= 90)) or (val = 180) then
- begin
- FSpotCutOff := val;
- NotifyChange(Self);
- end;
- end;
- end;
- procedure TgxLightSource.SetLightStyle(const val: TgxLightStyle);
- begin
- if FLightStyle <> val then
- begin
- FLightStyle := val;
- NotifyChange(Self);
- end;
- end;
- procedure TgxLightSource.SetAmbient(aValue: TgxColor);
- begin
- FAmbient.Color := aValue.Color;
- NotifyChange(Self);
- end;
- procedure TgxLightSource.SetDiffuse(aValue: TgxColor);
- begin
- FDiffuse.Color := aValue.Color;
- NotifyChange(Self);
- end;
- procedure TgxLightSource.SetSpecular(aValue: TgxColor);
- begin
- FSpecular.Color := aValue.Color;
- NotifyChange(Self);
- end;
- procedure TgxLightSource.SetConstAttenuation(aValue: Single);
- begin
- if FConstAttenuation <> aValue then
- begin
- FConstAttenuation := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxLightSource.SetLinearAttenuation(aValue: Single);
- begin
- if FLinearAttenuation <> aValue then
- begin
- FLinearAttenuation := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxLightSource.SetQuadraticAttenuation(aValue: Single);
- begin
- if FQuadraticAttenuation <> aValue then
- begin
- FQuadraticAttenuation := aValue;
- NotifyChange(Self);
- end;
- end;
- function TgxLightSource.Attenuated: Boolean;
- begin
- Result := (LightStyle <> lsParallel) and ((ConstAttenuation <> 1) or (LinearAttenuation <> 0) or (QuadraticAttenuation <> 0));
- end;
- // ------------------
- // ------------------ TgxScene ------------------
- // ------------------
- constructor TgxScene.Create(AOwner: TComponent);
- begin
- inherited;
- // root creation
- FCurrentBuffer := nil;
- FObjects := TgxSceneRootObject.Create(Self);
- FObjects.Name := 'ObjectRoot';
- FLights := TgxPersistentObjectList.Create;
- FObjectsSorting := osRenderBlendedLast;
- FVisibilityCulling := vcNone;
- // actual maximum number of lights is stored in TgxSceneViewer
- FLights.Count := 8;
- FInitializableObjects := TgxInitializableObjectList.Create;
- end;
- destructor TgxScene.Destroy;
- begin
- InitializableObjects.Free;
- FObjects.DestroyHandles;
- FLights.Free;
- FObjects.Free;
- if Assigned(FBuffers) then
- FreeAndNil(FBuffers);
- inherited Destroy;
- end;
- procedure TgxScene.AddLight(aLight: TgxLightSource);
- var
- i: Integer;
- begin
- for i := 0 to FLights.Count - 1 do
- if FLights.List^[i] = nil then
- begin
- FLights.List^[i] := aLight;
- aLight.FLightID := i;
- Break;
- end;
- end;
- procedure TgxScene.RemoveLight(aLight: TgxLightSource);
- var
- idx: Integer;
- begin
- idx := FLights.IndexOf(aLight);
- if idx >= 0 then
- FLights[idx] := nil;
- end;
- procedure TgxScene.AddLights(anObj: TgxBaseSceneObject);
- var
- i: Integer;
- begin
- if anObj is TgxLightSource then
- AddLight(TgxLightSource(anObj));
- for i := 0 to anObj.Count - 1 do
- AddLights(anObj.Children[i]);
- end;
- procedure TgxScene.RemoveLights(anObj: TgxBaseSceneObject);
- var
- i: Integer;
- begin
- if anObj is TgxLightSource then
- RemoveLight(TgxLightSource(anObj));
- for i := 0 to anObj.Count - 1 do
- RemoveLights(anObj.Children[i]);
- end;
- procedure TgxScene.ShutdownAllLights;
- procedure DoShutdownLight(obj: TgxBaseSceneObject);
- var
- i: Integer;
- begin
- if obj is TgxLightSource then
- TgxLightSource(obj).Shining := False;
- for i := 0 to obj.Count - 1 do
- DoShutdownLight(obj[i]);
- end;
- begin
- DoShutdownLight(FObjects);
- end;
- procedure TgxScene.AddBuffer(aBuffer: TgxSceneBuffer);
- begin
- if not Assigned(FBuffers) then
- FBuffers := TgxPersistentObjectList.Create;
- if FBuffers.IndexOf(aBuffer) < 0 then
- begin
- FBuffers.Add(aBuffer);
- if FBaseContext = nil then
- FBaseContext := TgxSceneBuffer(FBuffers[0]).RenderingContext;
- if (FBuffers.Count > 1) and Assigned(FBaseContext) then
- aBuffer.RenderingContext.ShareLists(FBaseContext);
- end;
- end;
- procedure TgxScene.RemoveBuffer(aBuffer: TgxSceneBuffer);
- var
- i: Integer;
- begin
- if Assigned(FBuffers) then
- begin
- i := FBuffers.IndexOf(aBuffer);
- if i >= 0 then
- begin
- if FBuffers.Count = 1 then
- begin
- FreeAndNil(FBuffers);
- FBaseContext := nil;
- end
- else
- begin
- FBuffers.Delete(i);
- FBaseContext := TgxSceneBuffer(FBuffers[0]).RenderingContext;
- end;
- end;
- end;
- end;
- procedure TgxScene.GetChildren(AProc: TGetChildProc; Root: TComponent);
- begin
- FObjects.GetChildren(AProc, Root);
- end;
- procedure TgxScene.SetChildOrder(AChild: TComponent; Order: Integer);
- begin
- (AChild as TgxBaseSceneObject).Index := Order;
- end;
- function TgxScene.IsUpdating: Boolean;
- begin
- Result := (FUpdateCount <> 0) or (csLoading in ComponentState) or (csDestroying in ComponentState);
- end;
- procedure TgxScene.BeginUpdate;
- begin
- Inc(FUpdateCount);
- end;
- procedure TgxScene.EndUpdate;
- begin
- Assert(FUpdateCount > 0);
- Dec(FUpdateCount);
- if FUpdateCount = 0 then
- NotifyChange(Self);
- end;
- procedure TgxScene.SetObjectsSorting(const val: TgxObjectsSorting);
- begin
- if FObjectsSorting <> val then
- begin
- if val = osInherited then
- FObjectsSorting := osRenderBlendedLast
- else
- FObjectsSorting := val;
- NotifyChange(Self);
- end;
- end;
- procedure TgxScene.SetVisibilityCulling(const val: TgxVisibilityCulling);
- begin
- if FVisibilityCulling <> val then
- begin
- if val = vcInherited then
- FVisibilityCulling := vcNone
- else
- FVisibilityCulling := val;
- NotifyChange(Self);
- end;
- end;
- procedure TgxScene.ReadState(reader: TReader);
- var
- SaveRoot: TComponent;
- begin
- SaveRoot := reader.Root;
- try
- if Owner <> nil then
- reader.Root := Owner;
- inherited;
- finally
- reader.Root := SaveRoot;
- end;
- end;
- procedure TgxScene.Progress(const deltaTime, newTime: Double);
- var
- pt: TgxProgressTimes;
- begin
- pt.deltaTime := deltaTime;
- pt.newTime := newTime;
- FCurrentDeltaTime := deltaTime;
- if Assigned(FOnBeforeProgress) then
- FOnBeforeProgress(Self, deltaTime, newTime);
- FObjects.DoProgress(pt);
- if Assigned(FOnProgress) then
- FOnProgress(Self, deltaTime, newTime);
- end;
- procedure TgxScene.SaveToFile(const fileName: string);
- var
- stream: TStream;
- begin
- stream := TFileStream.Create(fileName, fmCreate);
- try
- SaveToStream(stream);
- finally
- stream.Free;
- end;
- end;
- procedure TgxScene.LoadFromFile(const fileName: string);
- procedure CheckResFileStream(stream: TStream);
- var
- n: Integer;
- B: Byte;
- begin
- n := stream.Position;
- stream.Read(B, SizeOf(B));
- stream.Position := n;
- if B = $FF then
- stream.ReadResHeader;
- end;
- var
- stream: TStream;
- begin
- stream := TFileStream.Create(fileName, fmOpenRead);
- try
- CheckResFileStream(stream);
- LoadFromStream(stream);
- finally
- stream.Free;
- end;
- end;
- procedure TgxScene.SaveToTextFile(const fileName: string);
- var
- mem: TMemoryStream;
- fil: TStream;
- begin
- mem := TMemoryStream.Create;
- fil := TFileStream.Create(fileName, fmCreate);
- try
- SaveToStream(mem);
- mem.Position := 0;
- ObjectBinaryToText(mem, fil);
- finally
- fil.Free;
- mem.Free;
- end;
- end;
- procedure TgxScene.LoadFromTextFile(const fileName: string);
- var
- mem: TMemoryStream;
- fil: TStream;
- begin
- mem := TMemoryStream.Create;
- fil := TFileStream.Create(fileName, fmOpenRead);
- try
- ObjectTextToBinary(fil, mem);
- mem.Position := 0;
- LoadFromStream(mem);
- finally
- fil.Free;
- mem.Free;
- end;
- end;
- procedure TgxScene.LoadFromStream(aStream: TStream);
- var
- fixups: TStringList;
- i: Integer;
- obj: TgxBaseSceneObject;
- begin
- fixups := TStringList.Create;
- try
- if Assigned(FBuffers) then
- begin
- for i := 0 to FBuffers.Count - 1 do
- fixups.AddObject(TgxSceneBuffer(FBuffers[i]).Camera.Name, FBuffers[i]);
- end;
- ShutdownAllLights;
- // will remove Viewer from FBuffers
- Objects.DeleteChildren;
- aStream.ReadComponent(Self);
- for i := 0 to fixups.Count - 1 do
- begin
- obj := FindSceneObject(fixups[i]);
- if obj is TgxCamera then
- TgxSceneBuffer(fixups.Objects[i]).Camera := TgxCamera(obj)
- else { can assign default camera (if existing, of course) instead }
- ;
- end;
- finally
- fixups.Free;
- end;
- end;
- procedure TgxScene.SaveToStream(aStream: TStream);
- begin
- aStream.WriteComponent(Self);
- end;
- function TgxScene.FindSceneObject(const aName: string): TgxBaseSceneObject;
- begin
- Result := FObjects.FindChild(aName, False);
- end;
- function TgxScene.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
- intersectNormal: PVector4f = nil): TgxBaseSceneObject;
- var
- bestDist2: Single;
- bestHit: TgxBaseSceneObject;
- iPoint, iNormal: TVector4f;
- pINormal: PVector4f;
- function RecursiveDive(baseObject: TgxBaseSceneObject): TgxBaseSceneObject;
- var
- i: Integer;
- curObj: TgxBaseSceneObject;
- dist2: Single;
- fNear, fFar: Single;
- begin
- Result := nil;
- for i := 0 to baseObject.Count - 1 do
- begin
- curObj := baseObject.Children[i];
- if curObj.Visible then
- begin
- if RayCastAABBIntersect(rayStart, rayVector, curObj.AxisAlignedBoundingBoxAbsoluteEx, fNear, fFar) then
- begin
- if fNear * fNear > bestDist2 then
- begin
- if not PointInAABB(rayStart, curObj.AxisAlignedBoundingBoxAbsoluteEx) then
- continue;
- end;
- if curObj.RayCastIntersect(rayStart, rayVector, @iPoint, pINormal) then
- begin
- dist2 := VectorDistance2(rayStart, iPoint);
- if dist2 < bestDist2 then
- begin
- bestHit := curObj;
- bestDist2 := dist2;
- if Assigned(intersectPoint) then
- intersectPoint^ := iPoint;
- if Assigned(intersectNormal) then
- intersectNormal^ := iNormal;
- end;
- end;
- RecursiveDive(curObj);
- end;
- end;
- end;
- end;
- begin
- bestDist2 := 1E20;
- bestHit := nil;
- if Assigned(intersectNormal) then
- pINormal := @iNormal
- else
- pINormal := nil;
- RecursiveDive(Objects);
- Result := bestHit;
- end;
- procedure TgxScene.NotifyChange(Sender: TObject);
- var
- i: Integer;
- begin
- if (not IsUpdating) and Assigned(FBuffers) then
- for i := 0 to FBuffers.Count - 1 do
- TgxSceneBuffer(FBuffers[i]).NotifyChange(Self);
- end;
- procedure TgxScene.SetupLights(maxLights: Integer);
- var
- i: Integer;
- lightSource: TgxLightSource;
- nbLights: Integer;
- lPos: TVector4f;
- begin
- nbLights := FLights.Count;
- if nbLights > maxLights then
- nbLights := maxLights;
- // setup all light sources
- with CurrentContext.gxStates, CurrentContext.PipeLineTransformation do
- begin
- for i := 0 to nbLights - 1 do
- begin
- lightSource := TgxLightSource(FLights[i]);
- if Assigned(lightSource) then
- with lightSource do
- begin
- LightEnabling[FLightID] := Shining;
- if Shining then
- begin
- if FixedFunctionPipeLight then
- begin
- RebuildMatrix;
- if LightStyle in [lsParallel, lsParallelSpot] then
- begin
- SetModelMatrix(AbsoluteMatrix);
- glLightfv(GL_LIGHT0 + FLightID, GL_POSITION, SpotDirection.AsAddress);
- end
- else
- begin
- SetModelMatrix(Parent.AbsoluteMatrix);
- glLightfv(GL_LIGHT0 + FLightID, GL_POSITION, Position.AsAddress);
- end;
- if LightStyle in [lsSpot, lsParallelSpot] then
- begin
- if FSpotCutOff <> 180 then
- glLightfv(GL_LIGHT0 + FLightID, GL_SPOT_DIRECTION, FSpotDirection.AsAddress);
- end;
- end;
- lPos := lightSource.AbsolutePosition;
- if LightStyle in [lsParallel, lsParallelSpot] then
- lPos.W := 0.0
- else
- lPos.W := 1.0;
- LightPosition[FLightID] := lPos;
- LightSpotDirection[FLightID] := lightSource.SpotDirection.AsAffineVector;
- LightAmbient[FLightID] := FAmbient.Color;
- LightDiffuse[FLightID] := FDiffuse.Color;
- LightSpecular[FLightID] := FSpecular.Color;
- LightConstantAtten[FLightID] := FConstAttenuation;
- LightLinearAtten[FLightID] := FLinearAttenuation;
- LightQuadraticAtten[FLightID] := FQuadraticAttenuation;
- LightSpotExponent[FLightID] := FSpotExponent;
- LightSpotCutoff[FLightID] := FSpotCutOff;
- end;
- end
- else
- LightEnabling[i] := False;
- end;
- // turn off other lights
- for i := nbLights to maxLights - 1 do
- LightEnabling[i] := False;
- SetModelMatrix(IdentityHmgMatrix);
- end;
- end;
- // ------------------
- // ------------------ TgxFogEnvironment ------------------
- // ------------------
- // Note: The fog implementation is not conformal with the rest of the scene management
- // because it is viewer bound not scene bound.
- constructor TgxFogEnvironment.Create(AOwner: TPersistent);
- begin
- inherited;
- FSceneBuffer := (AOwner as TgxSceneBuffer);
- FFogColor := TgxColor.CreateInitialized(Self, clrBlack);
- FFogMode := fmLinear;
- FFogStart := 10;
- FFogEnd := 1000;
- FFogDistance := fdDefault;
- end;
- destructor TgxFogEnvironment.Destroy;
- begin
- FFogColor.Free;
- inherited Destroy;
- end;
- procedure TgxFogEnvironment.SetFogColor(Value: TgxColor);
- begin
- if Assigned(Value) then
- begin
- FFogColor.Assign(Value);
- NotifyChange(Self);
- end;
- end;
- procedure TgxFogEnvironment.SetFogStart(Value: Single);
- begin
- if Value <> FFogStart then
- begin
- FFogStart := Value;
- NotifyChange(Self);
- end;
- end;
- procedure TgxFogEnvironment.SetFogEnd(Value: Single);
- begin
- if Value <> FFogEnd then
- begin
- FFogEnd := Value;
- NotifyChange(Self);
- end;
- end;
- procedure TgxFogEnvironment.Assign(Source: TPersistent);
- begin
- if Source is TgxFogEnvironment then
- begin
- FFogColor.Assign(TgxFogEnvironment(Source).FFogColor);
- FFogStart := TgxFogEnvironment(Source).FFogStart;
- FFogEnd := TgxFogEnvironment(Source).FFogEnd;
- FFogMode := TgxFogEnvironment(Source).FFogMode;
- FFogDistance := TgxFogEnvironment(Source).FFogDistance;
- NotifyChange(Self);
- end;
- inherited;
- end;
- function TgxFogEnvironment.IsAtDefaultValues: Boolean;
- begin
- Result := VectorEquals(FogColor.Color, FogColor.DefaultColor) and (FogStart = 10) and (FogEnd = 1000) and (FogMode = fmLinear)
- and (FogDistance = fdDefault);
- end;
- procedure TgxFogEnvironment.SetFogMode(Value: TgxFogMode);
- begin
- if Value <> FFogMode then
- begin
- FFogMode := Value;
- NotifyChange(Self);
- end;
- end;
- procedure TgxFogEnvironment.SetFogDistance(const val: TgxFogDistance);
- begin
- if val <> FFogDistance then
- begin
- FFogDistance := val;
- NotifyChange(Self);
- end;
- end;
- var
- vImplemDependantFogDistanceDefault: Integer = -1;
- procedure TgxFogEnvironment.ApplyFog;
- var
- tempActivation: Boolean;
- begin
- with FSceneBuffer do
- begin
- if not Assigned(FRenderingContext) then
- Exit;
- tempActivation := not FRenderingContext.Active;
- if tempActivation then
- FRenderingContext.Activate;
- end;
- case FFogMode of
- fmLinear:
- glFogi(GL_FOG_MODE, GL_LINEAR);
- fmExp:
- begin
- glFogi(GL_FOG_MODE, GL_EXP);
- glFogf(GL_FOG_DENSITY, FFogColor.alpha);
- end;
- fmExp2:
- begin
- glFogi(GL_FOG_MODE, GL_EXP2);
- glFogf(GL_FOG_DENSITY, FFogColor.alpha);
- end;
- end;
- glFogfv(GL_FOG_COLOR, FFogColor.AsAddress);
- glFogf(GL_FOG_START, FFogStart);
- glFogf(GL_FOG_END, FFogEnd);
- case FogDistance of
- fdDefault:
- begin
- if vImplemDependantFogDistanceDefault = -1 then
- glGetIntegerv(Cardinal(GL_FOG_DISTANCE_MODE_NV), // GL_FOG_DISTANCE_MODE_NV,
- @vImplemDependantFogDistanceDefault)
- else
- glFogi(Cardinal(GL_FOG_DISTANCE_MODE_NV), vImplemDependantFogDistanceDefault);
- end;
- fdEyePlane:
- glFogi(Cardinal(GL_FOG_DISTANCE_MODE_NV), GL_EYE_PLANE_ABSOLUTE_NV);
- fdEyeRadial:
- glFogi(GL_FOG_DISTANCE_MODE_NV, GL_EYE_RADIAL_NV);
- else
- Assert(False);
- end;
- if tempActivation then
- FSceneBuffer.RenderingContext.Deactivate;
- end;
- // ------------------
- // ------------------ TgxSceneBuffer ------------------
- // ------------------
- constructor TgxSceneBuffer.Create(AOwner: TPersistent);
- begin
- inherited Create(AOwner);
- // initialize private state variables
- FFogEnvironment := TgxFogEnvironment.Create(Self);
- FBackgroundColor := TColors.SysBtnFace;
- FBackgroundAlpha := 1;
- FAmbientColor := TgxColor.CreateInitialized(Self, clrGray20);
- FDepthTest := True;
- FFaceCulling := True;
- FLighting := True;
- FAntiAliasing := aaDefault;
- FDepthPrecision := dpDefault;
- FColorDepth := cdDefault;
- FShadeModel := smDefault;
- FFogEnable := False;
- FLayer := clMainPlane;
- FAfterRenderEffects := TgxPersistentObjectList.Create;
- FContextOptions := [roDoubleBuffer, roRenderToWindow, roDebugContext];
- ResetPerformanceMonitor;
- end;
- destructor TgxSceneBuffer.Destroy;
- begin
- Melt;
- DestroyRC;
- FAmbientColor.Free;
- FAfterRenderEffects.Free;
- FFogEnvironment.Free;
- inherited Destroy;
- end;
- procedure TgxSceneBuffer.PrepareGLContext;
- begin
- if Assigned(FOnPrepareGLContext) then
- FOnPrepareGLContext(Self);
- end;
- procedure TgxSceneBuffer.SetupRCOptions(Context: TgxContext);
- const
- cColorDepthToColorBits: array [cdDefault .. cdFloat128bits] of Integer = (24, 8, 16, 24, 64, 128); // float_type
- cDepthPrecisionToDepthBits: array [dpDefault .. dp32bits] of Integer = (24, 16, 24, 32);
- var
- locOptions: TgxRCOptions;
- locStencilBits, locAlphaBits, locColorBits: Integer;
- begin
- locOptions := [];
- if roDoubleBuffer in ContextOptions then
- locOptions := locOptions + [rcoDoubleBuffered];
- if roStereo in ContextOptions then
- locOptions := locOptions + [rcoStereo];
- if roDebugContext in ContextOptions then
- locOptions := locOptions + [rcoDebug];
- if roOpenGL_ES2_Context in ContextOptions then
- locOptions := locOptions + [rcoOGL_ES];
- if roNoColorBuffer in ContextOptions then
- locColorBits := 0
- else
- locColorBits := cColorDepthToColorBits[ColorDepth];
- if roStencilBuffer in ContextOptions then
- locStencilBits := 8
- else
- locStencilBits := 0;
- if roDestinationAlpha in ContextOptions then
- locAlphaBits := 8
- else
- locAlphaBits := 0;
- with Context do
- begin
- if roSoftwareMode in ContextOptions then
- Acceleration := chaSoftware
- else
- Acceleration := chaHardware;
- Options := locOptions;
- ColorBits := locColorBits;
- DepthBits := cDepthPrecisionToDepthBits[DepthPrecision];
- StencilBits := locStencilBits;
- AlphaBits := locAlphaBits;
- AccumBits := AccumBufferBits;
- AuxBuffers := 0;
- AntiAliasing := Self.AntiAliasing;
- Layer := Self.Layer;
- { gxStates.ForwardContext := roForwardContext in ContextOptions; }
- PrepareGLContext;
- end;
- end;
- procedure TgxSceneBuffer.CreateRC(AWindowHandle: THandle; memoryContext: Boolean; BufferCount: Integer);
- begin
- DestroyRC;
- FRendering := True;
- try
- // will be freed in DestroyWindowHandle
- FRenderingContext := GXContextManager.CreateContext;
- if not Assigned(FRenderingContext) then
- raise Exception.Create('Failed to create RenderingContext.');
- SetupRCOptions(FRenderingContext);
- if Assigned(FCamera) and Assigned(FCamera.FScene) then
- FCamera.FScene.AddBuffer(Self);
- with FRenderingContext do
- begin
- try
- if memoryContext then
- CreateMemoryContext(AWindowHandle, FViewPort.width, FViewPort.height, BufferCount)
- else
- CreateContext(AWindowHandle);
- except
- FreeAndNil(FRenderingContext);
- raise;
- end;
- end;
- FRenderingContext.Activate;
- try
- // this one should NOT be replaced with an assert
- if (GL_VERSION < 1.1) then
- begin
- ShowMessage(strWrongVersion);
- Abort;
- end;
- // define viewport, this is necessary because the first WM_SIZE message
- // is posted before the rendering context has been created
- FRenderingContext.gxStates.viewport := Vector4iMake(FViewPort.Left, FViewPort.Top, FViewPort.width, FViewPort.height);
- // set up initial context states
- SetupRenderingContext(FRenderingContext);
- FRenderingContext.gxStates.ColorClearValue := ConvertWinColor(FBackgroundColor);
- finally
- FRenderingContext.Deactivate;
- end;
- finally
- FRendering := False;
- end;
- end;
- procedure TgxSceneBuffer.DestroyRC;
- begin
- if Assigned(FRenderingContext) then
- begin
- Melt;
- // for some obscure reason, Mesa3D doesn't like this call... any help welcome
- FreeAndNil(FSelector);
- FreeAndNil(FRenderingContext);
- if Assigned(FCamera) and Assigned(FCamera.FScene) then
- FCamera.FScene.RemoveBuffer(Self);
- end;
- end;
- function TgxSceneBuffer.RCInstantiated: Boolean;
- begin
- Result := Assigned(FRenderingContext);
- end;
- procedure TgxSceneBuffer.Resize(newLeft, newTop, newWidth, newHeight: Integer);
- begin
- if newWidth < 1 then
- newWidth := 1;
- if newHeight < 1 then
- newHeight := 1;
- FViewPort.Left := newLeft;
- FViewPort.Top := newTop;
- FViewPort.width := newWidth;
- FViewPort.height := newHeight;
- if Assigned(FRenderingContext) then
- begin
- FRenderingContext.Activate;
- try
- // Part of workaround for MS OpenGL "black borders" bug
- FRenderingContext.gxStates.viewport := Vector4iMake(FViewPort.Left, FViewPort.Top, FViewPort.width, FViewPort.height);
- finally
- FRenderingContext.Deactivate;
- end;
- end;
- end;
- function TgxSceneBuffer.Acceleration: TgxContextAcceleration;
- begin
- if Assigned(FRenderingContext) then
- Result := FRenderingContext.Acceleration
- else
- Result := chaUnknown;
- end;
- procedure TgxSceneBuffer.SetupRenderingContext(Context: TgxContext);
- procedure SetState(bool: Boolean; csState: TgxState);
- begin
- case bool of
- True:
- Context.gxStates.PerformEnable(csState);
- False:
- Context.gxStates.PerformDisable(csState);
- end;
- end;
- var
- LColorDepth: Cardinal;
- begin
- if not Assigned(Context) then
- Exit;
- if not(roForwardContext in ContextOptions) then
- begin
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT, FAmbientColor.AsAddress);
- if roTwoSideLighting in FContextOptions then
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE)
- else
- glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
- glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
- case ShadeModel of
- smDefault, smSmooth:
- glShadeModel(GL_SMOOTH);
- smFlat:
- glShadeModel(GL_FLAT);
- else
- Assert(False, strErrorEx + strUnknownType);
- end;
- end;
- with Context.gxStates do
- begin
- Enable(stNormalize);
- SetState(DepthTest, stDepthTest);
- SetState(FaceCulling, stCullFace);
- SetState(Lighting, stLighting);
- SetState(FogEnable, stFog);
- Disable(stDepthClamp);
- if not(roForwardContext in ContextOptions) then
- begin
- glGetIntegerv(GL_BLUE_BITS, @LColorDepth); // could've used red or green too
- SetState((LColorDepth < 8), stDither);
- end;
- ResetAllTextureMatrix;
- end;
- end;
- function TgxSceneBuffer.GetLimit(Which: TLimitType): Integer;
- var
- VP: array [0 .. 1] of Double;
- begin
- case Which of
- limClipPlanes:
- glGetIntegerv(GL_MAX_CLIP_PLANES, @Result);
- limEvalOrder:
- glGetIntegerv(GL_MAX_EVAL_ORDER, @Result);
- limLights:
- glGetIntegerv(GL_MAX_LIGHTS, @Result);
- limListNesting:
- glGetIntegerv(GL_MAX_LIST_NESTING, @Result);
- limModelViewStack:
- glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, @Result);
- limNameStack:
- glGetIntegerv(GL_MAX_NAME_STACK_DEPTH, @Result);
- limPixelMapTable:
- glGetIntegerv(GL_MAX_PIXEL_MAP_TABLE, @Result);
- limProjectionStack:
- glGetIntegerv(GL_MAX_PROJECTION_STACK_DEPTH, @Result);
- limTextureSize:
- glGetIntegerv(GL_MAX_TEXTURE_SIZE, @Result);
- limTextureStack:
- glGetIntegerv(GL_MAX_TEXTURE_STACK_DEPTH, @Result);
- limViewportDims:
- begin
- glGetDoublev(GL_MAX_VIEWPORT_DIMS, @VP);
- if VP[0] > VP[1] then
- Result := Round(VP[0])
- else
- Result := Round(VP[1]);
- end;
- limAccumAlphaBits: glGetIntegerv(GL_ACCUM_ALPHA_BITS, @Result);
- limAccumBlueBits: glGetIntegerv(GL_ACCUM_BLUE_BITS, @Result);
- limAccumGreenBits: glGetIntegerv(GL_ACCUM_GREEN_BITS, @Result);
- limAccumRedBits: glGetIntegerv(GL_ACCUM_RED_BITS, @Result);
- limAlphaBits: glGetIntegerv(GL_ALPHA_BITS, @Result);
- limAuxBuffers: glGetIntegerv(GL_AUX_BUFFERS, @Result);
- limDepthBits: glGetIntegerv(GL_DEPTH_BITS, @Result);
- limStencilBits: glGetIntegerv(GL_STENCIL_BITS, @Result);
- limBlueBits: glGetIntegerv(GL_BLUE_BITS, @Result);
- limGreenBits: glGetIntegerv(GL_GREEN_BITS, @Result);
- limRedBits: glGetIntegerv(GL_RED_BITS, @Result);
- limIndexBits: glGetIntegerv(GL_INDEX_BITS, @Result);
- limStereo: glGetIntegerv(GL_STEREO, @Result);
- limDoubleBuffer: glGetIntegerv(GL_DOUBLEBUFFER, @Result);
- limSubpixelBits: glGetIntegerv(GL_SUBPIXEL_BITS, @Result);
- limNbTextureUnits: glGetIntegerv(GL_MAX_TEXTURE_UNITS_ARB, @Result);
- else
- Result := 0;
- end;
- end;
- procedure TgxSceneBuffer.RenderToFile(const AFile: string; DPI: Integer);
- var
- ABitmap: TBitmap;
- saveAllowed: Boolean;
- fileName: string;
- begin
- Assert((not FRendering), strAlreadyRendering);
- ABitmap := TBitmap.Create;
- try
- ABitmap.width := FViewPort.width;
- ABitmap.height := FViewPort.height;
- { TODO -oPW : E2129 Cannot assign to a read-only property }
- // aBitmap.PixelFormat := glpf24Bit;
- RenderToBitmap(ABitmap, DPI);
- fileName := AFile;
- if fileName = '' then
- saveAllowed := SavePictureDialog(fileName)
- else
- saveAllowed := True;
- if saveAllowed then
- begin
- if FileExists(fileName) then
- saveAllowed := QuestionDlg(Format('Overwrite file %s?', [fileName]));
- if saveAllowed then
- ABitmap.SaveToFile(fileName);
- end;
- finally
- ABitmap.Free;
- end;
- end;
- procedure TgxSceneBuffer.RenderToFile(const AFile: string; bmpWidth, bmpHeight: Integer);
- var
- ABitmap: TBitmap;
- saveAllowed: Boolean;
- fileName: string;
- begin
- Assert((not FRendering), strAlreadyRendering);
- ABitmap := TBitmap.Create;
- try
- ABitmap.width := bmpWidth;
- ABitmap.height := bmpHeight;
- { TODO -oPW : E2129 Cannot assign to a read-only property }
- (* GLS-> aBitmap.PixelFormat := glpf24Bit; *)
- RenderToBitmap(ABitmap,
- // GLS-> (GetDeviceLogicalPixelsX(Cardinal(ABitmap.Canvas.Handle)) * bmpWidth) div
- (GetDeviceLogicalPixelsX(ABitmap.Handle) * bmpWidth) div FViewPort.width);
- fileName := AFile;
- if fileName = '' then
- saveAllowed := SavePictureDialog(fileName)
- else
- saveAllowed := True;
- if saveAllowed then
- begin
- if FileExists(fileName) then
- saveAllowed := QuestionDlg(Format('Overwrite file %s?', [fileName]));
- if saveAllowed then
- ABitmap.SaveToFile(fileName);
- end;
- finally
- ABitmap.Free;
- end;
- end;
- function TgxSceneBuffer.CreateSnapShot: TgxBitmap32;
- begin
- Result := TgxBitmap32.Create;
- Result.width := FViewPort.width;
- Result.height := FViewPort.height;
- if Assigned(Camera) and Assigned(Camera.Scene) then
- begin
- FRenderingContext.Activate;
- try
- Result.ReadPixels(rect(0, 0, FViewPort.width, FViewPort.height));
- finally
- FRenderingContext.Deactivate;
- end;
- end;
- end;
- function TgxSceneBuffer.CreateSnapShotBitmap: TBitmap;
- var
- bmp32: TgxBitmap32;
- begin
- bmp32 := CreateSnapShot;
- try
- Result := bmp32.Create32BitsBitmap;
- finally
- bmp32.Free;
- end;
- end;
- procedure TgxSceneBuffer.CopyToTexture(aTexture: TgxTexture);
- begin
- CopyToTexture(aTexture, 0, 0, width, height, 0, 0);
- end;
- procedure TgxSceneBuffer.CopyToTexture(aTexture: TgxTexture; xSrc, ySrc, AWidth, AHeight: Integer; xDest, yDest: Integer;
- glCubeFace: GLEnum = 0);
- var
- bindTarget: TglTextureTarget;
- begin
- if RenderingContext <> nil then
- begin
- RenderingContext.Activate;
- try
- if not(aTexture.Image is TgxBlankImage) then
- aTexture.ImageClassName := TgxBlankImage.ClassName;
- if aTexture.Image.width <> AWidth then
- TgxBlankImage(aTexture.Image).width := AWidth;
- if aTexture.Image.height <> AHeight then
- TgxBlankImage(aTexture.Image).height := AHeight;
- if aTexture.Image.Depth <> 0 then
- TgxBlankImage(aTexture.Image).Depth := 0;
- if TgxBlankImage(aTexture.Image).CubeMap <> (glCubeFace > 0) then
- TgxBlankImage(aTexture.Image).CubeMap := (glCubeFace > 0);
- bindTarget := aTexture.Image.NativeTextureTarget;
- RenderingContext.gxStates.TextureBinding[0, bindTarget] := aTexture.Handle;
- if glCubeFace > 0 then
- glCopyTexSubImage2D(glCubeFace, 0, xDest, yDest, xSrc, ySrc, AWidth, AHeight)
- else
- glCopyTexSubImage2D(DecodeTextureTarget(bindTarget), 0, xDest, yDest, xSrc, ySrc, AWidth, AHeight)
- finally
- RenderingContext.Deactivate;
- end;
- end;
- end;
- procedure TgxSceneBuffer.SaveAsFloatToFile(const aFilename: string);
- var
- Data: Pointer;
- DataSize: Integer;
- stream: TMemoryStream;
- const
- FloatSize = 4;
- begin
- if Assigned(Camera) and Assigned(Camera.Scene) then
- begin
- DataSize := width * height * FloatSize * FloatSize;
- GetMem(Data, DataSize);
- FRenderingContext.Activate;
- try
- glReadPixels(0, 0, width, height, GL_RGBA, GL_FLOAT, Data);
- glGetError;
- stream := TMemoryStream.Create;
- try
- stream.Write(Data^, DataSize);
- stream.SaveToFile(aFilename);
- finally
- stream.Free;
- end;
- finally
- FRenderingContext.Deactivate;
- FreeMem(Data);
- end;
- end;
- end;
- procedure TgxSceneBuffer.SetViewPort(x, y, W, H: Integer);
- begin
- with FViewPort do
- begin
- Left := x;
- Top := y;
- width := W;
- height := H;
- end;
- NotifyChange(Self);
- end;
- function TgxSceneBuffer.width: Integer;
- begin
- Result := FViewPort.width;
- end;
- function TgxSceneBuffer.height: Integer;
- begin
- Result := FViewPort.height;
- end;
- procedure TgxSceneBuffer.Freeze;
- begin
- if Freezed then
- Exit;
- if RenderingContext = nil then
- Exit;
- Render;
- FFreezed := True;
- RenderingContext.Activate;
- try
- FFreezeBuffer := AllocMem(FViewPort.width * FViewPort.height * 4);
- glReadPixels(0, 0, FViewPort.width, FViewPort.height, GL_RGBA, GL_UNSIGNED_BYTE, FFreezeBuffer);
- FFreezedViewPort := FViewPort;
- finally
- RenderingContext.Deactivate;
- end;
- end;
- procedure TgxSceneBuffer.Melt;
- begin
- if not Freezed then
- Exit;
- FreeMem(FFreezeBuffer);
- FFreezeBuffer := nil;
- FFreezed := False;
- end;
- procedure TgxSceneBuffer.RenderToBitmap(ABitmap: TBitmap; DPI: Integer);
- var
- nativeContext: TgxContext;
- aColorBits: Integer;
- begin
- Assert((not FRendering), strAlreadyRendering);
- FRendering := True;
- nativeContext := RenderingContext;
- try
- aColorBits := PixelFormatToColorBits(ABitmap.PixelFormat);
- if aColorBits < 8 then
- aColorBits := 8;
- FRenderingContext := GXContextManager.CreateContext;
- SetupRCOptions(FRenderingContext);
- with FRenderingContext do
- begin
- Options := []; // no such things for bitmap rendering
- ColorBits := aColorBits; // honour Bitmap's pixel depth
- AntiAliasing := aaNone; // no AA for bitmap rendering
- CreateContext(ABitmap.Handle); // CreateContext(ABitmap.Canvas.Handle);
- end;
- try
- FRenderingContext.Activate;
- try
- SetupRenderingContext(FRenderingContext);
- FRenderingContext.gxStates.ColorClearValue := ConvertWinColor(FBackgroundColor);
- // set the desired viewport and limit output to this rectangle
- with FViewPort do
- begin
- Left := 0;
- Top := 0;
- width := ABitmap.width;
- height := ABitmap.height;
- FRenderingContext.gxStates.viewport := Vector4iMake(Left, Top, width, height);
- end;
- ClearBuffers;
- FRenderDPI := DPI;
- if FRenderDPI = 0 then
- FRenderDPI := GetDeviceLogicalPixelsX(ABitmap.Handle);
- // render
- DoBaseRender(FViewPort, FRenderDPI, dsPrinting, nil);
- if nativeContext <> nil then
- FViewPort := TRectangle(nativeContext.gxStates.viewport);
- glFinish;
- finally
- FRenderingContext.Deactivate;
- end;
- finally
- FRenderingContext.Free;
- end;
- finally
- FRenderingContext := nativeContext;
- FRendering := False;
- end;
- if Assigned(FAfterRender) then
- if Owner is TComponent then
- if not(csDesigning in TComponent(Owner).ComponentState) then
- FAfterRender(Self);
- end;
- procedure TgxSceneBuffer.ShowInfo(Modal: Boolean);
- begin
- if not Assigned(FRenderingContext) then
- Exit;
- // most info is available with active context only
- FRenderingContext.Activate;
- try
- InvokeInfoForm(Self, Modal);
- finally
- FRenderingContext.Deactivate;
- end;
- end;
- procedure TgxSceneBuffer.ResetPerformanceMonitor;
- begin
- FFramesPerSecond := 0;
- FFrameCount := 0;
- FFirstPerfCounter := 0;
- end;
- procedure TgxSceneBuffer.PushViewMatrix(const newMatrix: TMatrix4f);
- var
- n: Integer;
- begin
- n := Length(FViewMatrixStack);
- SetLength(FViewMatrixStack, n + 1);
- FViewMatrixStack[n] := RenderingContext.PipeLineTransformation.ViewMatrix^;
- RenderingContext.PipeLineTransformation.SetViewMatrix(newMatrix);
- end;
- procedure TgxSceneBuffer.PopViewMatrix;
- var
- n: Integer;
- begin
- n := High(FViewMatrixStack);
- Assert(n >= 0, 'Unbalanced PopViewMatrix');
- RenderingContext.PipeLineTransformation.SetViewMatrix(FViewMatrixStack[n]);
- SetLength(FViewMatrixStack, n);
- end;
- procedure TgxSceneBuffer.PushProjectionMatrix(const newMatrix: TMatrix4f);
- var
- n: Integer;
- begin
- n := Length(FProjectionMatrixStack);
- SetLength(FProjectionMatrixStack, n + 1);
- FProjectionMatrixStack[n] := RenderingContext.PipeLineTransformation.ProjectionMatrix^;
- RenderingContext.PipeLineTransformation.SetProjectionMatrix(newMatrix);
- end;
- procedure TgxSceneBuffer.PopProjectionMatrix;
- var
- n: Integer;
- begin
- n := High(FProjectionMatrixStack);
- Assert(n >= 0, 'Unbalanced PopProjectionMatrix');
- RenderingContext.PipeLineTransformation.SetProjectionMatrix(FProjectionMatrixStack[n]);
- SetLength(FProjectionMatrixStack, n);
- end;
- function TgxSceneBuffer.ProjectionMatrix;
- begin
- Result := RenderingContext.PipeLineTransformation.ProjectionMatrix^;
- end;
- function TgxSceneBuffer.ViewMatrix: TMatrix4f;
- begin
- Result := RenderingContext.PipeLineTransformation.ViewMatrix^;
- end;
- function TgxSceneBuffer.ModelMatrix: TMatrix4f;
- begin
- Result := RenderingContext.PipeLineTransformation.ModelMatrix^;
- end;
- function TgxSceneBuffer.OrthoScreenToWorld(screenX, screenY: Integer): TAffineVector;
- var
- camPos, camUp, camRight: TAffineVector;
- f: Single;
- begin
- if Assigned(FCamera) then
- begin
- SetVector(camPos, FCameraAbsolutePosition);
- if Camera.TargetObject <> nil then
- begin
- SetVector(camUp, FCamera.AbsoluteUpVectorToTarget);
- SetVector(camRight, FCamera.AbsoluteRightVectorToTarget);
- end
- else
- begin
- SetVector(camUp, Camera.AbsoluteUp);
- SetVector(camRight, Camera.AbsoluteRight);
- end;
- f := 100 * FCamera.NearPlaneBias / (FCamera.FocalLength * FCamera.SceneScale);
- if FViewPort.width > FViewPort.height then
- f := f / FViewPort.width
- else
- f := f / FViewPort.height;
- SetVector(Result, VectorCombine3(camPos, camUp, camRight, 1, (screenY - (FViewPort.height div 2)) * f,
- (screenX - (FViewPort.width div 2)) * f));
- end
- else
- Result := NullVector;
- end;
- function TgxSceneBuffer.ScreenToWorld(const aPoint: TAffineVector): TAffineVector;
- var
- rslt: TVector4f;
- begin
- if Assigned(FCamera) and UnProject(VectorMake(aPoint), RenderingContext.PipeLineTransformation.ViewProjectionMatrix^,
- PHomogeneousIntVector(@FViewPort)^, rslt) then
- Result := Vector3fMake(rslt)
- else
- Result := aPoint;
- end;
- function TgxSceneBuffer.ScreenToWorld(const aPoint: TVector4f): TVector4f;
- begin
- MakePoint(Result, ScreenToWorld(AffineVectorMake(aPoint)));
- end;
- function TgxSceneBuffer.ScreenToWorld(screenX, screenY: Integer): TAffineVector;
- begin
- Result := ScreenToWorld(AffineVectorMake(screenX, FViewPort.height - screenY, 0));
- end;
- function TgxSceneBuffer.WorldToScreen(const aPoint: TAffineVector): TAffineVector;
- var
- rslt: TVector4f;
- begin
- RenderingContext.Activate;
- try
- PrepareRenderingMatrices(FViewPort, FRenderDPI);
- if Assigned(FCamera) and Project(VectorMake(aPoint), RenderingContext.PipeLineTransformation.ViewProjectionMatrix^,
- TVector4i(FViewPort), rslt) then
- Result := Vector3fMake(rslt)
- else
- Result := aPoint;
- finally
- RenderingContext.Deactivate;
- end;
- end;
- function TgxSceneBuffer.WorldToScreen(const aPoint: TVector4f): TVector4f;
- begin
- SetVector(Result, WorldToScreen(AffineVectorMake(aPoint)));
- end;
- procedure TgxSceneBuffer.WorldToScreen(points: PVector4f; nbPoints: Integer);
- var
- i: Integer;
- begin
- if Assigned(FCamera) then
- begin
- for i := nbPoints - 1 downto 0 do
- begin
- Project(points^, RenderingContext.PipeLineTransformation.ViewProjectionMatrix^,
- PHomogeneousIntVector(@FViewPort)^, points^);
- Inc(points);
- end;
- end;
- end;
- function TgxSceneBuffer.ScreenToVector(const aPoint: TAffineVector): TAffineVector;
- begin
- Result := VectorSubtract(ScreenToWorld(aPoint), PAffineVector(@FCameraAbsolutePosition)^);
- end;
- function TgxSceneBuffer.ScreenToVector(const aPoint: TVector4f): TVector4f;
- begin
- SetVector(Result, VectorSubtract(ScreenToWorld(aPoint), FCameraAbsolutePosition));
- Result.W := 0;
- end;
- function TgxSceneBuffer.ScreenToVector(const x, y: Integer): TVector4f;
- var
- av: TAffineVector;
- begin
- av.x := x;
- av.y := y;
- av.z := 0;
- SetVector(Result, ScreenToVector(av));
- end;
- function TgxSceneBuffer.VectorToScreen(const VectToCam: TAffineVector): TAffineVector;
- begin
- Result := WorldToScreen(VectorAdd(VectToCam, PAffineVector(@FCameraAbsolutePosition)^));
- end;
- function TgxSceneBuffer.ScreenVectorIntersectWithPlane(const aScreenPoint: TVector4f; const planePoint, planeNormal: TVector4f;
- var intersectPoint: TVector4f): Boolean;
- var
- v: TVector4f;
- begin
- if Assigned(FCamera) then
- begin
- SetVector(v, ScreenToVector(aScreenPoint));
- Result := RayCastPlaneIntersect(FCameraAbsolutePosition, v, planePoint, planeNormal, @intersectPoint);
- intersectPoint.W := 1;
- end
- else
- Result := False;
- end;
- function TgxSceneBuffer.ScreenVectorIntersectWithPlaneXY(const aScreenPoint: TVector4f; const z: Single;
- var intersectPoint: TVector4f): Boolean;
- begin
- Result := ScreenVectorIntersectWithPlane(aScreenPoint, VectorMake(0, 0, z), ZHmgVector, intersectPoint);
- intersectPoint.W := 0;
- end;
- function TgxSceneBuffer.ScreenVectorIntersectWithPlaneYZ(const aScreenPoint: TVector4f; const x: Single;
- var intersectPoint: TVector4f): Boolean;
- begin
- Result := ScreenVectorIntersectWithPlane(aScreenPoint, VectorMake(x, 0, 0), XHmgVector, intersectPoint);
- intersectPoint.W := 0;
- end;
- function TgxSceneBuffer.ScreenVectorIntersectWithPlaneXZ(const aScreenPoint: TVector4f; const y: Single;
- var intersectPoint: TVector4f): Boolean;
- begin
- Result := ScreenVectorIntersectWithPlane(aScreenPoint, VectorMake(0, y, 0), YHmgVector, intersectPoint);
- intersectPoint.W := 0;
- end;
- function TgxSceneBuffer.PixelRayToWorld(x, y: Integer): TAffineVector;
- var
- dov, np, fp, z, dst, wrpdst: Single;
- vec, cam, targ, rayhit, pix: TAffineVector;
- camAng: real;
- begin
- if Camera.CameraStyle = csOrtho2D then
- dov := 2
- else
- dov := Camera.DepthOfView;
- np := Camera.NearPlane;
- fp := Camera.NearPlane + dov;
- z := GetPixelDepth(x, y);
- dst := (fp * np) / (fp - z * dov); // calc from z-buffer value to world depth
- // ------------------------
- // z:=1-(fp/d-1)/(fp/np-1); //calc from world depth to z-buffer value
- // ------------------------
- vec.x := x;
- vec.y := FViewPort.height - y;
- vec.z := 0;
- vec := ScreenToVector(vec);
- NormalizeVector(vec);
- SetVector(cam, Camera.AbsolutePosition);
- // targ:=Camera.TargetObject.Position.AsAffineVector;
- // SubtractVector(targ,cam);
- pix.x := FViewPort.width * 0.5;
- pix.y := FViewPort.height * 0.5;
- pix.z := 0;
- targ := Self.ScreenToVector(pix);
- camAng := VectorAngleCosine(targ, vec);
- wrpdst := dst / camAng;
- rayhit := cam;
- CombineVector(rayhit, vec, wrpdst);
- Result := rayhit;
- end;
- procedure TgxSceneBuffer.ClearBuffers;
- var
- bufferBits: GLbitfield;
- begin
- if roNoDepthBufferClear in ContextOptions then
- bufferBits := 0
- else
- begin
- bufferBits := GL_DEPTH_BUFFER_BIT;
- CurrentContext.gxStates.DepthWriteMask := True;
- end;
- if ContextOptions * [roNoColorBuffer, roNoColorBufferClear] = [] then
- begin
- bufferBits := bufferBits or GL_COLOR_BUFFER_BIT;
- CurrentContext.gxStates.SetColorMask(cAllColorComponents);
- end;
- if roStencilBuffer in ContextOptions then
- begin
- bufferBits := bufferBits or GL_STENCIL_BUFFER_BIT;
- end;
- if bufferBits <> 0 then
- glClear(bufferBits);
- end;
- procedure TgxSceneBuffer.NotifyChange(Sender: TObject);
- begin
- DoChange;
- end;
- procedure TgxSceneBuffer.PickObjects(const rect: TRect; pickList: TgxPickList; objectCountGuess: Integer);
- var
- i: Integer;
- obj: TgxBaseSceneObject;
- begin
- if not Assigned(FCamera) then
- Exit;
- Assert((not FRendering), strAlreadyRendering);
- Assert(Assigned(pickList));
- FRenderingContext.Activate;
- FRendering := True;
- try
- // Creates best selector which techniques is hardware can do
- if not Assigned(FSelector) then
- FSelector := GetBestSelectorClass.Create;
- xglMapTexCoordToNull; // turn off
- PrepareRenderingMatrices(FViewPort, RenderDPI, @rect);
- FSelector.Hits := -1;
- if objectCountGuess > 0 then
- FSelector.objectCountGuess := objectCountGuess;
- repeat
- FSelector.Start;
- // render the scene (in select mode, nothing is drawn)
- FRenderDPI := 96;
- if Assigned(FCamera) and Assigned(FCamera.FScene) then
- RenderScene(FCamera.FScene, FViewPort.width, FViewPort.height, dsPicking, nil);
- until FSelector.Stop;
- FSelector.FillPickingList(pickList);
- for i := 0 to pickList.Count - 1 do
- begin
- obj := TgxBaseSceneObject(pickList[i]);
- if Assigned(obj.FOnPicked) then
- obj.FOnPicked(obj);
- end;
- finally
- FRendering := False;
- FRenderingContext.Deactivate;
- end;
- end;
- function TgxSceneBuffer.GetPickedObjects(const rect: TRect; objectCountGuess: Integer = 64): TgxPickList;
- begin
- Result := TgxPickList.Create(psMinDepth);
- PickObjects(rect, Result, objectCountGuess);
- end;
- function TgxSceneBuffer.GetPickedObject(x, y: Integer): TgxBaseSceneObject;
- var
- pkList: TgxPickList;
- begin
- pkList := GetPickedObjects(rect(x - 1, y - 1, x + 1, y + 1));
- try
- if pkList.Count > 0 then
- Result := TgxBaseSceneObject(pkList.Hit[0])
- else
- Result := nil;
- finally
- pkList.Free;
- end;
- end;
- function TgxSceneBuffer.GetPixelColor(x, y: Integer): TColor;
- var
- buf: array [0 .. 2] of Byte;
- begin
- if not Assigned(FCamera) then
- begin
- Result := 0;
- Exit;
- end;
- FRenderingContext.Activate;
- try
- glReadPixels(x, FViewPort.height - y, 1, 1, GL_RGB, GL_UNSIGNED_BYTE, @buf[0]);
- finally
- FRenderingContext.Deactivate;
- end;
- Result := RGB(buf[0], buf[1], buf[2]);
- end;
- function TgxSceneBuffer.GetPixelDepth(x, y: Integer): Single;
- begin
- if not Assigned(FCamera) then
- begin
- Result := 0;
- Exit;
- end;
- FRenderingContext.Activate;
- try
- glReadPixels(x, FViewPort.height - y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, @Result);
- finally
- FRenderingContext.Deactivate;
- end;
- end;
- function TgxSceneBuffer.PixelDepthToDistance(aDepth: Single): Single;
- var
- dov, np, fp: Single;
- begin
- if Camera.CameraStyle = csOrtho2D then
- dov := 2
- else
- dov := Camera.DepthOfView; // Depth of View (from np to fp)
- np := Camera.NearPlane; // Near plane distance
- fp := np + dov; // Far plane distance
- Result := (fp * np) / (fp - aDepth * dov);
- // calculate world distance from z-buffer value
- end;
- function TgxSceneBuffer.PixelToDistance(x, y: Integer): Single;
- var
- z, dov, np, fp, dst, camAng: Single;
- norm, coord, vec: TAffineVector;
- begin
- z := GetPixelDepth(x, y);
- if Camera.CameraStyle = csOrtho2D then
- dov := 2
- else
- dov := Camera.DepthOfView; // Depth of View (from np to fp)
- np := Camera.NearPlane; // Near plane distance
- fp := np + dov; // Far plane distance
- dst := (np * fp) / (fp - z * dov);
- // calculate from z-buffer value to frustrum depth
- coord.x := x;
- coord.y := y;
- vec := Self.ScreenToVector(coord); // get the pixel vector
- coord.x := FViewPort.width div 2;
- coord.y := FViewPort.height div 2;
- norm := Self.ScreenToVector(coord); // get the absolute camera direction
- camAng := VectorAngleCosine(norm, vec);
- Result := dst / camAng; // compensate for flat frustrum face
- end;
- procedure TgxSceneBuffer.NotifyMouseMove(Shift: TShiftState; x, y: Single);
- begin
- // Nothing
- end;
- procedure TgxSceneBuffer.PrepareRenderingMatrices(const AViewport: TRectangle; resolution: Integer; pickingRect: PRect = nil);
- begin
- RenderingContext.PipeLineTransformation.IdentityAll;
- // setup projection matrix
- if Assigned(pickingRect) then
- begin
- CurrentContext.PipeLineTransformation.SetProjectionMatrix(CreatePickMatrix((pickingRect^.Left + pickingRect^.Right) div 2,
- FViewPort.height - ((pickingRect^.Top + pickingRect^.Bottom) div 2), Abs(pickingRect^.Right - pickingRect^.Left),
- Abs(pickingRect^.Bottom - pickingRect^.Top), TVector4i(FViewPort)));
- end;
- FBaseProjectionMatrix := CurrentContext.PipeLineTransformation.ProjectionMatrix^;
- if Assigned(FCamera) then
- begin
- FCamera.Scene.FCurrentCamera := FCamera;
- // apply camera perpective
- FCamera.ApplyPerspective(AViewport, FViewPort.width, FViewPort.height, resolution);
- // setup model view matrix
- // apply camera transformation (viewpoint)
- FCamera.Apply;
- FCameraAbsolutePosition := FCamera.AbsolutePosition;
- end;
- end;
- procedure TgxSceneBuffer.DoBaseRender(const AViewport: TRectangle; resolution: Integer; drawState: TgxDrawState;
- baseObject: TgxBaseSceneObject);
- begin
- with RenderingContext.gxStates do
- begin
- PrepareRenderingMatrices(AViewport, resolution);
- { if not ForwardContext then }
- begin
- xglMapTexCoordToNull; // force XGL rebind
- xglMapTexCoordToMain;
- end;
- if Assigned(FViewerBeforeRender) and (drawState <> dsPrinting) then
- FViewerBeforeRender(Self);
- if Assigned(FBeforeRender) then
- if Owner is TComponent then
- if not(csDesigning in TComponent(Owner).ComponentState) then
- FBeforeRender(Self);
- if Assigned(FCamera) and Assigned(FCamera.FScene) then
- begin
- with FCamera.FScene do
- begin
- SetupLights(maxLights);
- // if not ForwardContext then
- begin
- if FogEnable then
- begin
- Enable(stFog);
- FogEnvironment.ApplyFog;
- end
- else
- Disable(stFog);
- end;
- RenderScene(FCamera.FScene, AViewport.width, AViewport.height, drawState, baseObject);
- end;
- end;
- if Assigned(FPostRender) then
- if Owner is TComponent then
- if not(csDesigning in TComponent(Owner).ComponentState) then
- FPostRender(Self);
- end;
- Assert(Length(FViewMatrixStack) = 0, 'Unbalance Push/PopViewMatrix.');
- Assert(Length(FProjectionMatrixStack) = 0, 'Unbalance Push/PopProjectionMatrix.');
- end;
- procedure TgxSceneBuffer.Render;
- begin
- Render(nil);
- end;
- procedure TgxSceneBuffer.Render(baseObject: TgxBaseSceneObject);
- var
- perfCounter, framePerf: Int64;
- begin
- if FRendering then
- Exit;
- if not Assigned(FRenderingContext) then
- Exit;
- if Freezed and (FFreezeBuffer <> nil) then
- begin
- RenderingContext.Activate;
- try
- RenderingContext.gxStates.ColorClearValue := ConvertWinColor(FBackgroundColor, FBackgroundAlpha);
- ClearBuffers;
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity;
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity;
- glRasterPos2f(-1, -1);
- glDrawPixels(FFreezedViewPort.width, FFreezedViewPort.height, GL_RGBA, GL_UNSIGNED_BYTE, FFreezeBuffer);
- if not(roNoSwapBuffers in ContextOptions) then
- RenderingContext.SwapBuffers;
- finally
- RenderingContext.Deactivate;
- end;
- Exit;
- end;
- QueryPerformanceCounter(framePerf);
- if Assigned(FCamera) and Assigned(FCamera.FScene) then
- begin
- FCamera.AbsoluteMatrixAsAddress;
- FCamera.FScene.AddBuffer(Self);
- end;
- FRendering := True;
- try
- FRenderingContext.Activate;
- try
- if FFrameCount = 0 then
- QueryPerformanceCounter(FFirstPerfCounter);
- FRenderDPI := 96; // default value for screen
- SetupRenderingContext(FRenderingContext);
- // clear the buffers
- FRenderingContext.gxStates.ColorClearValue := ConvertWinColor(FBackgroundColor, FBackgroundAlpha);
- ClearBuffers;
- // render
- DoBaseRender(FViewPort, RenderDPI, dsRendering, baseObject);
- if not(roNoSwapBuffers in ContextOptions) then
- RenderingContext.SwapBuffers;
- // yes, calculate average frames per second...
- Inc(FFrameCount);
- QueryPerformanceCounter(perfCounter);
- FLastFrameTime := (perfCounter - framePerf) / vCounterFrequency;
- Dec(perfCounter, FFirstPerfCounter);
- if perfCounter > 0 then
- FFramesPerSecond := (FFrameCount * vCounterFrequency) / perfCounter;
- finally
- FRenderingContext.Deactivate;
- end;
- if Assigned(FAfterRender) and (Owner is TComponent) then
- if not(csDesigning in TComponent(Owner).ComponentState) then
- FAfterRender(Self);
- finally
- FRendering := False;
- end;
- end;
- procedure TgxSceneBuffer.RenderScene(aScene: TgxScene; const viewPortSizeX, viewPortSizeY: Integer; drawState: TgxDrawState;
- baseObject: TgxBaseSceneObject);
- var
- i: Integer;
- rci: TgxRenderContextInfo;
- rightVector: TVector4f;
- begin
- FAfterRenderEffects.Clear;
- aScene.FCurrentBuffer := Self;
- FillChar(rci, SizeOf(rci), 0);
- rci.Scene := aScene;
- rci.Buffer := Self;
- rci.afterRenderEffects := FAfterRenderEffects;
- rci.ObjectsSorting := aScene.ObjectsSorting;
- rci.VisibilityCulling := aScene.VisibilityCulling;
- rci.bufferFaceCull := FFaceCulling;
- rci.bufferLighting := FLighting;
- rci.bufferFog := FFogEnable;
- rci.bufferDepthTest := FDepthTest;
- rci.drawState := drawState;
- rci.sceneAmbientColor := FAmbientColor.Color;
- rci.primitiveMask := cAllMeshPrimitive;
- with FCamera do
- begin
- rci.cameraPosition := FCameraAbsolutePosition;
- rci.cameraDirection := FLastDirection;
- NormalizeVector(rci.cameraDirection);
- rci.cameraDirection.W := 0;
- rightVector := VectorCrossProduct(rci.cameraDirection, Up.AsVector);
- rci.cameraUp := VectorCrossProduct(rightVector, rci.cameraDirection);
- NormalizeVector(rci.cameraUp);
- with rci.rcci do
- begin
- origin := rci.cameraPosition;
- clippingDirection := rci.cameraDirection;
- viewPortRadius := FViewPortRadius;
- nearClippingDistance := FNearPlane;
- farClippingDistance := FNearPlane + FDepthOfView;
- frustum := RenderingContext.PipeLineTransformation.frustum;
- end;
- end;
- rci.viewPortSize.cx := viewPortSizeX;
- rci.viewPortSize.cy := viewPortSizeY;
- rci.RenderDPI := FRenderDPI;
- rci.gxStates := RenderingContext.gxStates;
- rci.PipeLineTransformation := RenderingContext.PipeLineTransformation;
- rci.proxySubObject := False;
- rci.ignoreMaterials := (roNoColorBuffer in FContextOptions) or (rci.drawState = dsPicking);
- rci.amalgamating := rci.drawState = dsPicking;
- rci.gxStates.SetColorWriting(not rci.ignoreMaterials);
- if Assigned(FInitiateRendering) then
- FInitiateRendering(Self, rci);
- if aScene.InitializableObjects.Count <> 0 then
- begin
- // First initialize all objects and delete them from the list.
- for i := aScene.InitializableObjects.Count - 1 downto 0 do
- begin
- aScene.InitializableObjects.Items[i].InitializeObject( { Self? } aScene, rci);
- aScene.InitializableObjects.Delete(i);
- end;
- end;
- if RenderingContext.IsPraparationNeed then
- RenderingContext.PrepareHandlesData;
- if baseObject = nil then
- begin
- aScene.Objects.Render(rci);
- end
- else
- baseObject.Render(rci);
- rci.gxStates.SetColorWriting(True);
- with FAfterRenderEffects do
- if Count > 0 then
- for i := 0 to Count - 1 do
- TgxObjectAfterEffect(Items[i]).Render(rci);
- if Assigned(FWrapUpRendering) then
- FWrapUpRendering(Self, rci);
- end;
- procedure TgxSceneBuffer.SetBackgroundColor(AColor: TColor);
- begin
- if FBackgroundColor <> AColor then
- begin
- FBackgroundColor := AColor;
- NotifyChange(Self);
- end;
- end;
- procedure TgxSceneBuffer.SetBackgroundAlpha(alpha: Single);
- begin
- if FBackgroundAlpha <> alpha then
- begin
- FBackgroundAlpha := alpha;
- NotifyChange(Self);
- end;
- end;
- procedure TgxSceneBuffer.SetAmbientColor(AColor: TgxColor);
- begin
- FAmbientColor.Assign(AColor);
- end;
- procedure TgxSceneBuffer.SetCamera(ACamera: TgxCamera);
- begin
- if FCamera <> ACamera then
- begin
- if Assigned(FCamera) then
- begin
- if Assigned(FCamera.FScene) then
- FCamera.FScene.RemoveBuffer(Self);
- FCamera := nil;
- end;
- if Assigned(ACamera) and Assigned(ACamera.FScene) then
- begin
- FCamera := ACamera;
- FCamera.TransformationChanged;
- end;
- NotifyChange(Self);
- end;
- end;
- procedure TgxSceneBuffer.SetContextOptions(Options: TContextOptions);
- begin
- if FContextOptions <> Options then
- begin
- FContextOptions := Options;
- DoStructuralChange;
- end;
- end;
- procedure TgxSceneBuffer.SetDepthTest(aValue: Boolean);
- begin
- if FDepthTest <> aValue then
- begin
- FDepthTest := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxSceneBuffer.SetFaceCulling(aValue: Boolean);
- begin
- if FFaceCulling <> aValue then
- begin
- FFaceCulling := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxSceneBuffer.SetLayer(const Value: TgxContextLayer);
- begin
- if FLayer <> Value then
- begin
- FLayer := Value;
- DoStructuralChange;
- end;
- end;
- procedure TgxSceneBuffer.SetLighting(aValue: Boolean);
- begin
- if FLighting <> aValue then
- begin
- FLighting := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxSceneBuffer.SetAntiAliasing(const val: TgxAntiAliasing);
- begin
- if FAntiAliasing <> val then
- begin
- FAntiAliasing := val;
- DoStructuralChange;
- end;
- end;
- procedure TgxSceneBuffer.SetDepthPrecision(const val: TgxDepthPrecision);
- begin
- if FDepthPrecision <> val then
- begin
- FDepthPrecision := val;
- DoStructuralChange;
- end;
- end;
- procedure TgxSceneBuffer.SetColorDepth(const val: TgxColorDepth);
- begin
- if FColorDepth <> val then
- begin
- FColorDepth := val;
- DoStructuralChange;
- end;
- end;
- procedure TgxSceneBuffer.SetShadeModel(const val: TgxShadeModel);
- begin
- if FShadeModel <> val then
- begin
- FShadeModel := val;
- NotifyChange(Self);
- end;
- end;
- procedure TgxSceneBuffer.SetFogEnable(aValue: Boolean);
- begin
- if FFogEnable <> aValue then
- begin
- FFogEnable := aValue;
- NotifyChange(Self);
- end;
- end;
- procedure TgxSceneBuffer.SetFogEnvironment(aValue: TgxFogEnvironment);
- begin
- FFogEnvironment.Assign(aValue);
- NotifyChange(Self);
- end;
- function TgxSceneBuffer.StoreFog: Boolean;
- begin
- Result := (not FFogEnvironment.IsAtDefaultValues);
- end;
- procedure TgxSceneBuffer.SetAccumBufferBits(const val: Integer);
- begin
- if FAccumBufferBits <> val then
- begin
- FAccumBufferBits := val;
- DoStructuralChange;
- end;
- end;
- procedure TgxSceneBuffer.DoChange;
- begin
- if (not FRendering) and Assigned(FOnChange) then
- FOnChange(Self);
- end;
- procedure TgxSceneBuffer.DoStructuralChange;
- var
- bCall: Boolean;
- begin
- if Assigned(Owner) then
- bCall := not(csLoading in TComponent(GetOwner).ComponentState)
- else
- bCall := True;
- if bCall and Assigned(FOnStructuralChange) then
- FOnStructuralChange(Self);
- end;
- // ------------------
- // ------------------ TgxNonVisualViewer ------------------
- // ------------------
- constructor TgxNonVisualViewer.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FWidth := 256;
- FHeight := 256;
- FBuffer := TgxSceneBuffer.Create(Self);
- FBuffer.OnChange := DoBufferChange;
- FBuffer.OnStructuralChange := DoBufferStructuralChange;
- FBuffer.OnPrepareGLContext := DoOnPrepareVXContext;
- end;
- destructor TgxNonVisualViewer.Destroy;
- begin
- FBuffer.Free;
- inherited Destroy;
- end;
- procedure TgxNonVisualViewer.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- if (Operation = opRemove) and (AComponent = Camera) then
- Camera := nil;
- inherited;
- end;
- procedure TgxNonVisualViewer.CopyToTexture(aTexture: TgxTexture);
- begin
- CopyToTexture(aTexture, 0, 0, width, height, 0, 0);
- end;
- procedure TgxNonVisualViewer.CopyToTexture(aTexture: TgxTexture; xSrc, ySrc, width, height: Integer; xDest, yDest: Integer);
- begin
- Buffer.CopyToTexture(aTexture, xSrc, ySrc, width, height, xDest, yDest);
- end;
- procedure TgxNonVisualViewer.CopyToTextureMRT(aTexture: TgxTexture; BufferIndex: Integer);
- begin
- CopyToTextureMRT(aTexture, 0, 0, width, height, 0, 0, BufferIndex);
- end;
- procedure TgxNonVisualViewer.CopyToTextureMRT(aTexture: TgxTexture; xSrc, ySrc, width, height, xDest, yDest,
- BufferIndex: Integer);
- var
- target, Handle: Integer;
- buf: Pointer;
- createTexture: Boolean;
- procedure CreateNewTexture;
- begin
- GetMem(buf, width * height * 4);
- try // float_type
- glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buf);
- case aTexture.MinFilter of
- miNearest, miLinear:
- glTexImage2d(target, 0, aTexture.OpenGLTextureFormat, width, height,
- 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
- else
- if (target = GL_TEXTURE_2D) then
- begin
- // hardware-accelerated when supported
- glTexParameteri(target, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);
- glTexImage2d(target, 0, aTexture.OpenGLTextureFormat, width, height,
- 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
- end
- else
- begin
- glTexImage2d(target, 0, aTexture.OpenGLTextureFormat, width, height,
- 0, GL_RGBA, GL_UNSIGNED_BYTE, buf);
- glGenerateMipmap(target);
- end;
- end;
- finally
- FreeMem(buf);
- end;
- end;
- begin
- if Buffer.RenderingContext <> nil then
- begin
- Buffer.RenderingContext.Activate;
- try
- target := DecodeTextureTarget(aTexture.Image.NativeTextureTarget);
- createTexture := True;
- if aTexture.IsFloatType then
- begin // float_type special treatment
- createTexture := False;
- Handle := aTexture.Handle;
- end
- else if (target <> GL_TEXTURE_CUBE_MAP_ARB) or (FCubeMapRotIdx = 0) then
- begin
- createTexture := not aTexture.IsHandleAllocated;
- if createTexture then
- Handle := aTexture.AllocateHandle
- else
- Handle := aTexture.Handle;
- end
- else
- Handle := aTexture.Handle;
- // For MRT
- glReadBuffer(MRT_BUFFERS[BufferIndex]);
- Buffer.RenderingContext.gxStates.TextureBinding[0, EncodeGLTextureTarget(target)] := Handle;
- if target = GL_TEXTURE_CUBE_MAP_ARB then
- target := GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + FCubeMapRotIdx;
- if createTexture then
- CreateNewTexture
- else
- glCopyTexSubImage2D(target, 0, xDest, yDest, xSrc, ySrc, width, height);
- finally
- Buffer.RenderingContext.Deactivate;
- end;
- end;
- end;
- procedure TgxNonVisualViewer.SetupCubeMapCamera(Sender: TObject);
- (*
- const
- cFaceMat: array[0..5] of TGXMatrix =
- (
- (X: (X:0; Y:0; Z:-1; W:0);
- Y: (X:0; Y:-1; Z:0; W:0);
- Z: (X:-1; Y:0; Z:0; W:0);
- W: (X:0; Y:0; Z:0; W:1)),
- (X:(X:2.4335928828e-08; Y:0; Z:1; W:0);
- Y:(X:0; Y:-1; Z:0; W:0);
- Z:(X:1; Y:0; Z:-2.4335928828e-08; W:0);
- W:(X:0; Y:0; Z:0; W:1)),
- (X:(X:1; Y:1.2167964414e-08; Z:-1.4805936071e-16; W:0);
- Y:(X:0; Y:-1.2167964414e-08; Z:-1; W:0);
- Z:(X:-1.2167964414e-08; Y:1; Z:-1.2167964414e-08; W:0);
- W:(X:0; Y:0; Z:0; W:1)),
- (X:(X:1; Y:-1.2167964414e-08; Z:-1.4805936071e-16; W:0);
- Y:(X:0; Y:-1.2167964414e-08; Z:1; W:0);
- Z:(X:-1.2167964414e-08; Y:-1; Z:-1.2167964414e-08; W:0);
- W:(X:0; Y:0; Z:0; W:1)),
- (X:(X:1; Y:0; Z:-1.2167964414e-08; W:0);
- Y:(X:0; Y:-1; Z:0; W:0);
- Z:(X:-1.2167964414e-08; Y:0; Z:-1; W:0);
- W:(X:0; Y:0; Z:0; W:1)),
- (X:(X:-1; Y:0; Z:-1.2167964414e-08; W:0);
- Y:(X:0; Y:-1; Z:0; W:0);
- Z:(X:-1.2167964414e-08; Y:0; Z:1; W:0);
- W:(X:0; Y:0; Z:0; W:1))
- );
- *)
- var
- TM: TMatrix4f;
- begin
- // Setup appropriate FOV
- with CurrentContext.PipeLineTransformation do
- begin
- SetProjectionMatrix(CreatePerspectiveMatrix(90, 1, FCubeMapZNear, FCubeMapZFar));
- TM := CreateTranslationMatrix(FCubeMapTranslation);
- (* SetViewMatrix(MatrixMultiply(cFaceMat[FCubeMapRotIdx], TM)); *)
- end;
- end;
- procedure TgxNonVisualViewer.RenderCubeMapTextures(cubeMapTexture: TgxTexture; zNear: Single = 0; zFar: Single = 0);
- var
- oldEvent: TNotifyEvent;
- begin
- Assert((width = height), 'Memory Viewer must render to a square!');
- Assert(Assigned(FBuffer.FCamera), 'Camera not specified');
- Assert(Assigned(cubeMapTexture), 'Texture not specified');
- if zFar <= 0 then
- zFar := FBuffer.FCamera.DepthOfView;
- if zNear <= 0 then
- zNear := zFar * 0.001;
- oldEvent := FBuffer.FCamera.FDeferredApply;
- FBuffer.FCamera.FDeferredApply := SetupCubeMapCamera;
- FCubeMapZNear := zNear;
- FCubeMapZFar := zFar;
- VectorScale(FBuffer.FCamera.AbsolutePosition, -1, FCubeMapTranslation);
- try
- FCubeMapRotIdx := 0;
- while FCubeMapRotIdx < 6 do
- begin
- Render;
- Buffer.CopyToTexture(cubeMapTexture, 0, 0, Width, Height, 0, 0,
- GL_TEXTURE_CUBE_MAP_POSITIVE_X + FCubeMapRotIdx);
- Inc(FCubeMapRotIdx);
- end;
- finally
- FBuffer.FCamera.FDeferredApply := oldEvent;
- end;
- end;
- procedure TgxNonVisualViewer.SetBeforeRender(const val: TNotifyEvent);
- begin
- FBuffer.BeforeRender := val;
- end;
- function TgxNonVisualViewer.GetBeforeRender: TNotifyEvent;
- begin
- Result := FBuffer.BeforeRender;
- end;
- procedure TgxNonVisualViewer.SetPostRender(const val: TNotifyEvent);
- begin
- FBuffer.PostRender := val;
- end;
- function TgxNonVisualViewer.GetPostRender: TNotifyEvent;
- begin
- Result := FBuffer.PostRender;
- end;
- procedure TgxNonVisualViewer.SetAfterRender(const val: TNotifyEvent);
- begin
- FBuffer.AfterRender := val;
- end;
- function TgxNonVisualViewer.GetAfterRender: TNotifyEvent;
- begin
- Result := FBuffer.AfterRender;
- end;
- procedure TgxNonVisualViewer.SetCamera(const val: TgxCamera);
- begin
- FBuffer.Camera := val;
- end;
- function TgxNonVisualViewer.GetCamera: TgxCamera;
- begin
- Result := FBuffer.Camera;
- end;
- procedure TgxNonVisualViewer.SetBuffer(const val: TgxSceneBuffer);
- begin
- FBuffer.Assign(val);
- end;
- procedure TgxNonVisualViewer.DoOnPrepareVXContext(Sender: TObject);
- begin
- PrepareVXContext;
- end;
- procedure TgxNonVisualViewer.PrepareVXContext;
- begin
- // nothing, reserved for subclasses
- end;
- procedure TgxNonVisualViewer.DoBufferChange(Sender: TObject);
- begin
- // nothing, reserved for subclasses
- end;
- procedure TgxNonVisualViewer.DoBufferStructuralChange(Sender: TObject);
- begin
- FBuffer.DestroyRC;
- end;
- procedure TgxNonVisualViewer.SetWidth(const val: Integer);
- begin
- if val <> FWidth then
- begin
- FWidth := val;
- if FWidth < 1 then
- FWidth := 1;
- DoBufferStructuralChange(Self);
- end;
- end;
- procedure TgxNonVisualViewer.SetHeight(const val: Integer);
- begin
- if val <> FHeight then
- begin
- FHeight := val;
- if FHeight < 1 then
- FHeight := 1;
- DoBufferStructuralChange(Self);
- end;
- end;
- // ------------------
- // ------------------ TgxMemoryViewer ------------------
- // ------------------
- constructor TgxMemoryViewer.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- Width := 256;
- Height := 256;
- FBufferCount := 1;
- end;
- procedure TgxMemoryViewer.InstantiateRenderingContext;
- begin
- if FBuffer.RenderingContext = nil then
- begin
- FBuffer.SetViewPort(0, 0, Width, Height);
- FBuffer.CreateRC(HWND(0), True, FBufferCount);
- end;
- end;
- procedure TgxMemoryViewer.Render(baseObject: TgxBaseSceneObject = nil);
- begin
- InstantiateRenderingContext;
- FBuffer.Render(baseObject);
- end;
- procedure TgxMemoryViewer.SetBufferCount(const Value: Integer);
- const
- MaxAxuBufCount = 4; // Current hardware limit = 4
- begin
- if FBufferCount = Value then
- Exit;
- FBufferCount := Value;
- if FBufferCount < 1 then
- FBufferCount := 1;
- if FBufferCount > MaxAxuBufCount then
- FBufferCount := MaxAxuBufCount;
- // Request a new Instantiation of RC on next render
- FBuffer.DestroyRC;
- end;
- // ------------------
- // ------------------ TgxInitializableObjectList ------------------
- // ------------------
- function TgxInitializableObjectList.Add(const Item: IgxInitializable): Integer;
- begin
- Result := inherited Add(Pointer(Item));
- end;
- function TgxInitializableObjectList.GetItems(const Index: Integer): IgxInitializable;
- begin
- Result := IgxInitializable(inherited Get(Index));
- end;
- procedure TgxInitializableObjectList.PutItems(const Index: Integer; const Value: IgxInitializable);
- begin
- inherited Put(Index, Pointer(Value));
- end;
- // ------------------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------------------
- RegisterClasses([TgxLightSource, TgxCamera, TgxProxyObject, TgxScene, TgxDirectOpenGL, TgxRenderPoint, TgxMemoryViewer]);
- // preparation for high resolution timer
- QueryPerformanceFrequency(vCounterFrequency);
- end.
|