123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386 |
- //
- // The graphics engine GLXEngine. The unit of GXScene for Delphi
- //
- unit GXS.VectorFileObjects;
- (*
- Vector File related objects for GLScene
- The history is logged in a former GLS version of the unit.
- *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.Math,
- System.SysUtils,
- System.Types,
- Stage.VectorTypes,
- Stage.VectorGeometry,
- Stage.Strings,
- Stage.Utils,
- Stage.TextureFormat,
- GXS.BaseClasses,
- GXS.GeometryBB,
- GXS.VectorLists,
- GXS.PersistentClasses,
- GXS.Coordinates,
- GXS.XOpenGL,
- GXS.ApplicationFileIO,
- GXS.Scene,
- GXS.Texture,
- GXS.Material,
- GXS.Mesh,
- GXS.Octree,
- GXS.Silhouette,
- GXS.Context,
- GXS.Color,
- GXS.RenderContextInfo,
- GXS.State,
- GXS.ImageUtils,
- GXS.MeshUtils;
- type
- TgxMeshObjectList = class;
- TgxFaceGroups = class;
- TgxMeshAutoCentering = (macCenterX, macCenterY, macCenterZ, macUseBarycenter, macRestorePosition);
- TgxMeshAutoCenterings = set of TgxMeshAutoCentering;
- TgxMeshObjectMode = (momTriangles, momTriangleStrip, momFaceGroups);
- (* A base class for mesh objects.
- The class introduces a set of vertices and normals for the object but
- does no rendering of its own. *)
- TgxBaseMeshObject = class(TgxPersistentObject)
- private
- FName: string;
- FVertices: TgxAffineVectorList;
- FNormals: TgxAffineVectorList;
- FVisible: Boolean;
- protected
- procedure SetVertices(const val: TgxAffineVectorList);
- procedure SetNormals(const val: TgxAffineVectorList);
- procedure ContributeToBarycenter(var currentSum: TAffineVector; var nb: Integer); virtual;
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- // Clears all mesh object data, submeshes, facegroups, etc.
- procedure Clear; virtual;
- // Translates all the vertices by the given delta.
- procedure Translate(const delta: TAffineVector); virtual;
- (* Builds (smoothed) normals for the vertex list.
- If normalIndices is nil, the method assumes a bijection between
- vertices and normals sets, and when performed, Normals and Vertices
- list will have the same number of items (whatever previously was in
- the Normals list is ignored/removed).
- If normalIndices is defined, normals will be added to the list and
- their indices will be added to normalIndices. Already defined
- normals and indices are preserved.
- The only valid modes are currently momTriangles and momTriangleStrip
- (ie. momFaceGroups not supported). *)
- procedure BuildNormals(vertexIndices: TgxIntegerList; mode: TgxMeshObjectMode; normalIndices: TgxIntegerList = nil);
- (* Extracts all mesh triangles as a triangles list.
- The resulting list size is a multiple of 3, each group of 3 vertices
- making up and independant triangle.
- The returned list can be used independantly from the mesh object
- (all data is duplicated) and should be freed by caller.
- If texCoords is specified, per vertex texture coordinates will be
- placed there, when available. *)
- function ExtractTriangles(texCoords: TgxAffineVectorList = nil; normals: TgxAffineVectorList = nil): TgxAffineVectorList; virtual;
- property Name: string read FName write FName;
- property Visible: Boolean read FVisible write FVisible;
- property Vertices: TgxAffineVectorList read FVertices write SetVertices;
- property normals: TgxAffineVectorList read FNormals write SetNormals;
- end;
- TgxSkeletonFrameList = class;
- TgxSkeletonFrameTransform = (sftRotation, sftQuaternion);
- (* Stores position and rotation for skeleton joints.
- If you directly alter some values, make sure to call FlushLocalMatrixList
- so that the local matrices will be recalculated (the call to Flush does
- not recalculate the matrices, but marks the current ones as dirty). *)
- TgxSkeletonFrame = class(TgxPersistentObject)
- private
- FOwner: TgxSkeletonFrameList;
- FName: string;
- FPosition: TgxAffineVectorList;
- FRotation: TgxAffineVectorList;
- FQuaternion: TgxQuaternionList;
- FLocalMatrixList: PMatrixArray;
- FTransformMode: TgxSkeletonFrameTransform;
- protected
- procedure SetPosition(const val: TgxAffineVectorList);
- procedure SetRotation(const val: TgxAffineVectorList);
- procedure SetQuaternion(const val: TgxQuaternionList);
- public
- constructor CreateOwned(aOwner: TgxSkeletonFrameList);
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- property Owner: TgxSkeletonFrameList read FOwner;
- property Name: string read FName write FName;
- // Position values for the joints.
- property Position: TgxAffineVectorList read FPosition write SetPosition;
- // Rotation values for the joints.
- property Rotation: TgxAffineVectorList read FRotation write SetRotation;
- (* Quaternions are an alternative to Euler rotations to build the
- global matrices for the skeleton bones. *)
- property Quaternion: TgxQuaternionList read FQuaternion write SetQuaternion;
- (* TransformMode indicates whether to use Rotation or Quaternion to build
- the local transform matrices. *)
- property TransformMode: TgxSkeletonFrameTransform read FTransformMode write FTransformMode;
- (* Calculate or retrieves an array of local bone matrices.
- This array is calculated on the first call after creation, and the
- first call following a FlushLocalMatrixList. Subsequent calls return
- the same arrays. *)
- function LocalMatrixList: PMatrixArray;
- (* Flushes (frees) then LocalMatrixList data.
- Call this function to allow a recalculation of local matrices. *)
- procedure FlushLocalMatrixList;
- // As the name states; Convert Quaternions to Rotations or vice-versa.
- procedure ConvertQuaternionsToRotations(KeepQuaternions: Boolean = True);
- procedure ConvertRotationsToQuaternions(KeepRotations: Boolean = True);
- end;
- // A list of TgxSkeletonFrame objects.
- TgxSkeletonFrameList = class(TgxPersistentObjectList)
- private
- FOwner: TPersistent;
- protected
- function GetSkeletonFrame(Index: Integer): TgxSkeletonFrame;
- public
- constructor CreateOwned(aOwner: TPersistent);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- // As the name states; Convert Quaternions to Rotations or vice-versa.
- procedure ConvertQuaternionsToRotations(KeepQuaternions: Boolean = True; SetTransformMode: Boolean = True);
- procedure ConvertRotationsToQuaternions(KeepRotations: Boolean = True; SetTransformMode: Boolean = True);
- property Owner: TPersistent read FOwner;
- procedure Clear; override;
- property Items[Index: Integer]: TgxSkeletonFrame read GetSkeletonFrame; default;
- end;
- TgxSkeleton = class;
- TgxSkeletonBone = class;
- // A list of skeleton bones.
- TgxSkeletonBoneList = class(TgxPersistentObjectList)
- private
- FSkeleton: TgxSkeleton; // not persistent
- protected
- FGlobalMatrix: TMatrix4f;
- function GetSkeletonBone(Index: Integer): TgxSkeletonBone;
- procedure AfterObjectCreatedByReader(Sender: TObject); override;
- public
- constructor CreateOwned(aOwner: TgxSkeleton);
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- property Skeleton: TgxSkeleton read FSkeleton;
- property Items[Index: Integer]: TgxSkeletonBone read GetSkeletonBone; default;
- // Returns a bone by its BoneID, nil if not found.
- function BoneByID(anID: Integer): TgxSkeletonBone; virtual;
- // Returns a bone by its Name, nil if not found.
- function BoneByName(const aName: string): TgxSkeletonBone; virtual;
- // Number of bones (including all children and self).
- function BoneCount: Integer;
- // Render skeleton wireframe
- procedure BuildList(var mrci: TgxRenderContextInfo); virtual; abstract;
- procedure PrepareGlobalMatrices; virtual;
- end;
- // This list store skeleton root bones exclusively.
- TgxSkeletonRootBoneList = class(TgxSkeletonBoneList)
- public
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- // Render skeleton wireframe
- procedure BuildList(var mrci: TgxRenderContextInfo); override;
- property GlobalMatrix: TMatrix4f read FGlobalMatrix write FGlobalMatrix;
- end;
- (* A skeleton bone or node and its children.
- This class is the base item of the bones hierarchy in a skeletal model.
- The joint values are stored in a TgxSkeletonFrame, but the calculated bone
- matrices are stored here. *)
- TgxSkeletonBone = class(TgxSkeletonBoneList)
- private
- FOwner: TgxSkeletonBoneList; // indirectly persistent
- FBoneID: Integer;
- FName: string;
- FColor: Cardinal;
- protected
- function GetSkeletonBone(Index: Integer): TgxSkeletonBone;
- procedure SetColor(const val: Cardinal);
- public
- constructor CreateOwned(aOwner: TgxSkeletonBoneList);
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- // Render skeleton wireframe
- procedure BuildList(var mrci: TgxRenderContextInfo); override;
- property Owner: TgxSkeletonBoneList read FOwner;
- property Name: string read FName write FName;
- property BoneID: Integer read FBoneID write FBoneID;
- property Color: Cardinal read FColor write SetColor;
- property Items[Index: Integer]: TgxSkeletonBone read GetSkeletonBone; default;
- // Returns a bone by its BoneID, nil if not found.
- function BoneByID(anID: Integer): TgxSkeletonBone; override;
- function BoneByName(const aName: string): TgxSkeletonBone; override;
- // Set the bone's matrix. Becareful using this.
- procedure SetGlobalMatrix(Matrix: TMatrix4f); // Ragdoll
- // Set the bone's GlobalMatrix. Used for Ragdoll.
- procedure SetGlobalMatrixForRagDoll(RagDollMatrix: TMatrix4f); // Ragdoll
- (* Calculates the global matrix for the bone and its sub-bone.
- Call this function directly only the RootBone. *)
- procedure PrepareGlobalMatrices; override;
- (* Global Matrix for the bone in the current frame.
- Global matrices must be prepared by invoking PrepareGlobalMatrices
- on the root bone. *)
- property GlobalMatrix: TMatrix4f read FGlobalMatrix;
- // Free all sub bones and reset BoneID and Name.
- procedure Clean; override;
- end;
- TgxSkeletonColliderList = class;
- (* A general class storing the base level info required for skeleton
- based collision methods. This class is meant to be inherited from
- to create skeleton driven Verlet Constraints, ODE Geoms, etc.
- Overriden classes should be named as TSCxxxxx. *)
- TgxSkeletonCollider = class(TgxPersistentObject)
- private
- FOwner: TgxSkeletonColliderList;
- FBone: TgxSkeletonBone;
- FBoneID: Integer;
- FLocalMatrix, FGlobalMatrix: TMatrix4f;
- FAutoUpdate: Boolean;
- protected
- procedure SetBone(const val: TgxSkeletonBone);
- procedure SetLocalMatrix(const val: TMatrix4f);
- public
- constructor Create; override;
- constructor CreateOwned(aOwner: TgxSkeletonColliderList);
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- (* This method is used to align the colliders and their
- derived objects to their associated skeleton bone.
- Override to set up descendant class alignment properties. *)
- procedure AlignCollider; virtual;
- property Owner: TgxSkeletonColliderList read FOwner;
- // The bone that this collider associates with.
- property Bone: TgxSkeletonBone read FBone write SetBone;
- (* Offset and orientation of the collider in the associated
- bone's space. *)
- property LocalMatrix: TMatrix4f read FLocalMatrix write SetLocalMatrix;
- (* Global offset and orientation of the collider. This
- gets set in the AlignCollider method. *)
- property GlobalMatrix: TMatrix4f read FGlobalMatrix;
- property AutoUpdate: Boolean read FAutoUpdate write FAutoUpdate;
- end;
- // List class for storing TgxSkeletonCollider objects.
- TgxSkeletonColliderList = class(TgxPersistentObjectList)
- private
- FOwner: TPersistent;
- protected
- function GetSkeletonCollider(Index: Integer): TgxSkeletonCollider;
- public
- constructor CreateOwned(aOwner: TPersistent);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure Clear; override;
- // Calls AlignCollider for each collider in the list.
- procedure AlignColliders;
- property Owner: TPersistent read FOwner;
- property Items[Index: Integer]: TgxSkeletonCollider read GetSkeletonCollider; default;
- end;
- TgxBaseMesh = class;
- // Small structure to store a weighted lerp for use in blending.
- TGXBlendedLerpInfo = record
- frameIndex1, frameIndex2: Integer;
- lerpFactor: Single;
- weight: Single;
- externalPositions: TgxAffineVectorList;
- externalRotations: TgxAffineVectorList;
- externalQuaternions: TgxQuaternionList;
- end;
- (* Main skeleton object.
- This class stores the bones hierarchy and animation frames.
- It is also responsible for maintaining the "CurrentFrame" and allowing
- various frame blending operations. *)
- TgxSkeleton = class(TgxPersistentObject)
- private
- FOwner: TgxBaseMesh;
- FRootBones: TgxSkeletonRootBoneList;
- FFrames: TgxSkeletonFrameList;
- FCurrentFrame: TgxSkeletonFrame; // not persistent
- FBonesByIDCache: TList;
- FColliders: TgxSkeletonColliderList;
- FRagDollEnabled: Boolean; // ragdoll
- FMorphInvisibleParts: Boolean;
- protected
- procedure SetRootBones(const val: TgxSkeletonRootBoneList);
- procedure SetFrames(const val: TgxSkeletonFrameList);
- function GetCurrentFrame: TgxSkeletonFrame;
- procedure SetCurrentFrame(val: TgxSkeletonFrame);
- procedure SetColliders(const val: TgxSkeletonColliderList);
- public
- constructor CreateOwned(aOwner: TgxBaseMesh);
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- property Owner: TgxBaseMesh read FOwner;
- property RootBones: TgxSkeletonRootBoneList read FRootBones write SetRootBones;
- property Frames: TgxSkeletonFrameList read FFrames write SetFrames;
- property CurrentFrame: TgxSkeletonFrame read GetCurrentFrame write SetCurrentFrame;
- property Colliders: TgxSkeletonColliderList read FColliders write SetColliders;
- procedure FlushBoneByIDCache;
- function BoneByID(anID: Integer): TgxSkeletonBone;
- function BoneByName(const aName: string): TgxSkeletonBone;
- function BoneCount: Integer;
- procedure MorphTo(frameIndex: Integer); overload;
- procedure MorphTo(frame: TgxSkeletonFrame); overload;
- procedure Lerp(frameIndex1, frameIndex2: Integer; lerpFactor: Single);
- procedure BlendedLerps(const lerpInfos: array of TGXBlendedLerpInfo);
- (* Linearly removes the translation component between skeletal frames.
- This function will compute the translation of the first bone (index 0)
- and linearly subtract this translation in all frames between startFrame
- and endFrame. Its purpose is essentially to remove the 'slide' that
- exists in some animation formats (f.i. SMD). *)
- procedure MakeSkeletalTranslationStatic(startFrame, endFrame: Integer);
- (* Removes the absolute rotation component of the skeletal frames.
- Some formats will store frames with absolute rotation information,
- if this correct if the animation is the "main" animation.
- This function removes that absolute information, making the animation
- frames suitable for blending purposes. *)
- procedure MakeSkeletalRotationDelta(startFrame, endFrame: Integer);
- // Applies current frame to morph all mesh objects.
- procedure MorphMesh(normalize: Boolean);
- // Copy bone rotations from reference skeleton.
- procedure Synchronize(reference: TgxSkeleton);
- // Release bones and frames info.
- procedure Clear;
- // Backup and prepare the BoneMatrixInvertedMeshes to use with ragdolls
- procedure StartRagdoll; // ragdoll
- // Restore the BoneMatrixInvertedMeshes to stop the ragdoll
- procedure StopRagdoll; // ragdoll
- (* Turning this option off (by default) alows to increase FPS,
- but may break backwards-compatibility, because some may choose to
- attach other objects to invisible parts. *)
- property MorphInvisibleParts: Boolean read FMorphInvisibleParts write FMorphInvisibleParts;
- end;
- (* Rendering options per TgxMeshObject.
- moroGroupByMaterial : if set, the facegroups will be rendered by material
- in batchs, this will optimize rendering by reducing material switches, but
- also implies that facegroups will not be rendered in the order they are in
- the list. *)
- TgxMeshObjectRenderingOption = (moroGroupByMaterial);
- TgxMeshObjectRenderingOptions = set of TgxMeshObjectRenderingOption;
- TVBOBuffer = (vbVertices, vbNormals, vbColors, vbTexCoords, vbLightMapTexCoords, vbTexCoordsEx);
- TVBOBuffers = set of TVBOBuffer;
- (* Base mesh class.
- Introduces base methods and properties for mesh objects.
- Subclasses are named "TMOxxx". *)
- TgxMeshObject = class(TgxBaseMeshObject)
- private
- FOwner: TgxMeshObjectList;
- FExtentCacheRevision: Cardinal;
- FTexCoords: TgxAffineVectorList; // provision for 3D textures
- FLightMapTexCoords: TgxAffineVectorList; // reserved for 2D surface needs
- FColors: TgxVectorList;
- FFaceGroups: TgxFaceGroups;
- FMode: TgxMeshObjectMode;
- FRenderingOptions: TgxMeshObjectRenderingOptions;
- FArraysDeclared: Boolean; // not persistent
- FLightMapArrayEnabled: Boolean; // not persistent
- FLastLightMapIndex: Integer; // not persistent
- FTexCoordsEx: TList;
- FBinormalsTexCoordIndex: Integer;
- FTangentsTexCoordIndex: Integer;
- FLastXOpenGLTexMapping: Cardinal;
- FUseVBO: Boolean;
- FVerticesVBO: TgxVBOHandle;
- FNormalsVBO: TgxVBOHandle;
- FColorsVBO: TgxVBOHandle;
- FTexCoordsVBO: array of TgxVBOHandle;
- FLightmapTexCoordsVBO: TgxVBOHandle;
- FValidBuffers: TVBOBuffers;
- FExtentCache: TAABB;
- procedure SetUseVBO(const Value: Boolean);
- procedure SetValidBuffers(Value: TVBOBuffers);
- protected
- procedure SetTexCoords(const val: TgxAffineVectorList);
- procedure SetLightmapTexCoords(const val: TgxAffineVectorList);
- procedure SetColors(const val: TgxVectorList);
- procedure BufferArrays;
- procedure DeclareArraysToOpenGL(var mrci: TgxRenderContextInfo; evenIfAlreadyDeclared: Boolean = False);
- procedure DisableOpenGLArrays(var mrci: TgxRenderContextInfo);
- procedure EnableLightMapArray(var mrci: TgxRenderContextInfo);
- procedure DisableLightMapArray(var mrci: TgxRenderContextInfo);
- procedure SetTexCoordsEx(Index: Integer; const val: TgxVectorList);
- function GetTexCoordsEx(Index: Integer): TgxVectorList;
- procedure SetBinormals(const val: TgxVectorList);
- function GetBinormals: TgxVectorList;
- procedure SetBinormalsTexCoordIndex(const val: Integer);
- procedure SetTangents(const val: TgxVectorList);
- function GetTangents: TgxVectorList;
- procedure SetTangentsTexCoordIndex(const val: Integer);
- property ValidBuffers: TVBOBuffers read FValidBuffers write SetValidBuffers;
- public
- // Creates, assigns Owner and adds to list.
- constructor CreateOwned(aOwner: TgxMeshObjectList);
- constructor Create; override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure Clear; override;
- function ExtractTriangles(texCoords: TgxAffineVectorList = nil; normals: TgxAffineVectorList = nil): TgxAffineVectorList;
- override;
- // Returns number of triangles in the mesh object.
- function TriangleCount: Integer; virtual;
- procedure PrepareMaterialLibraryCache(matLib: TgxMaterialLibrary);
- procedure DropMaterialLibraryCache;
- (* Prepare the texture and materials before rendering.
- Invoked once, before building the list and NOT while building the list. *)
- procedure PrepareBuildList(var mrci: TgxRenderContextInfo); virtual;
- // Similar to regular scene object's BuildList method
- procedure BuildList(var mrci: TgxRenderContextInfo); virtual;
- // The extents of the object (min and max coordinates)
- procedure GetExtents(out min, max: TAffineVector); overload; virtual;
- procedure GetExtents(out aabb: TAABB); overload; virtual;
- // Barycenter from vertices data
- function GetBarycenter: TVector4f;
- // Precalculate whatever is needed for rendering, called once
- procedure Prepare; virtual;
- function PointInObject(const aPoint: TAffineVector): Boolean; virtual;
- // Returns the triangle data for a given triangle
- procedure GetTriangleData(tri: Integer; list: TgxAffineVectorList; var v0, v1, v2: TAffineVector); overload;
- procedure GetTriangleData(tri: Integer; list: TgxVectorList; var v0, v1, v2: TVector4f); overload;
- // Sets the triangle data of a given triangle
- procedure SetTriangleData(tri: Integer; list: TgxAffineVectorList; const v0, v1, v2: TAffineVector); overload;
- procedure SetTriangleData(tri: Integer; list: TgxVectorList; const v0, v1, v2: TVector4f); overload;
- (* Build the tangent space from the mesh object's vertex, normal
- and texcoord data, filling the binormals and tangents where
- specified. *)
- procedure BuildTangentSpace(buildBinormals: Boolean = True; buildTangents: Boolean = True);
- property Owner: TgxMeshObjectList read FOwner;
- property mode: TgxMeshObjectMode read FMode write FMode;
- property texCoords: TgxAffineVectorList read FTexCoords write SetTexCoords;
- property LightMapTexCoords: TgxAffineVectorList read FLightMapTexCoords write SetLightmapTexCoords;
- property Colors: TgxVectorList read FColors write SetColors;
- property FaceGroups: TgxFaceGroups read FFaceGroups;
- property RenderingOptions: TgxMeshObjectRenderingOptions read FRenderingOptions write FRenderingOptions;
- // If set, rendering will use VBO's instead of vertex arrays.
- property UseVBO: Boolean read FUseVBO write SetUseVBO;
- (* The TexCoords Extension is a list of vector lists that are used
- to extend the vertex data applied during rendering.
- The lists are applied to the GL_TEXTURE0_ARB + index texture
- environment. This means that if TexCoordsEx 0 or 1 have data it
- will override the TexCoords or LightMapTexCoords repectively.
- Lists are created on demand, meaning that if you request
- TexCoordsEx[4] it will create the list up to and including 4.
- The extensions are only applied to the texture environment if
- they contain data. *)
- property TexCoordsEx[index: Integer]: TgxVectorList read GetTexCoordsEx write SetTexCoordsEx;
- (* A TexCoordsEx list wrapper for binormals usage,
- returns TexCoordsEx[BinormalsTexCoordIndex]. *)
- property Binormals: TgxVectorList read GetBinormals write SetBinormals;
- (* A TexCoordsEx list wrapper for tangents usage,
- returns TexCoordsEx[BinormalsTexCoordIndex]. *)
- property Tangents: TgxVectorList read GetTangents write SetTangents;
- // Specify the texcoord extension index for binormals (default = 2)
- property BinormalsTexCoordIndex: Integer read FBinormalsTexCoordIndex write SetBinormalsTexCoordIndex;
- // Specify the texcoord extension index for tangents (default = 3)
- property TangentsTexCoordIndex: Integer read FTangentsTexCoordIndex write SetTangentsTexCoordIndex;
- end;
- // A list of TgxMeshObject objects.
- TgxMeshObjectList = class(TgxPersistentObjectList)
- private
- FOwner: TgxBaseMesh;
- // Resturns True if all its MeshObjects use VBOs.
- function GetUseVBO: Boolean;
- procedure SetUseVBO(const Value: Boolean);
- protected
- function GetMeshObject(Index: Integer): TgxMeshObject;
- public
- constructor CreateOwned(aOwner: TgxBaseMesh);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure PrepareMaterialLibraryCache(matLib: TgxMaterialLibrary);
- procedure DropMaterialLibraryCache;
- (* Prepare the texture and materials before rendering.
- Invoked once, before building the list and NOT while building the list. *)
- procedure PrepareBuildList(var mrci: TgxRenderContextInfo); virtual;
- // Similar to regular scene object's BuildList method
- procedure BuildList(var mrci: TgxRenderContextInfo); virtual;
- procedure MorphTo(morphTargetIndex: Integer);
- procedure Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single);
- function MorphTargetCount: Integer;
- procedure GetExtents(out min, max: TAffineVector);
- procedure Translate(const delta: TAffineVector);
- function ExtractTriangles(texCoords: TgxAffineVectorList = nil; normals: TgxAffineVectorList = nil): TgxAffineVectorList;
- // Returns number of triangles in the meshes of the list.
- function TriangleCount: Integer;
- (* Build the tangent space from the mesh object's vertex, normal
- and texcoord data, filling the binormals and tangents where
- specified. *)
- procedure BuildTangentSpace(buildBinormals: Boolean = True; buildTangents: Boolean = True);
- (* If set, rendering will use VBO's instead of vertex arrays.
- Resturns True if all its MeshObjects use VBOs. *)
- property UseVBO: Boolean read GetUseVBO write SetUseVBO;
- // Precalculate whatever is needed for rendering, called once
- procedure Prepare; virtual;
- function FindMeshByName(MeshName: string): TgxMeshObject;
- property Owner: TgxBaseMesh read FOwner;
- procedure Clear; override;
- property Items[Index: Integer]: TgxMeshObject read GetMeshObject; default;
- end;
- TgxMeshObjectListClass = class of TgxMeshObjectList;
- TgxMeshMorphTargetList = class;
- // A morph target, stores alternate lists of vertices and normals.
- TgxMeshMorphTarget = class(TgxBaseMeshObject)
- private
- FOwner: TgxMeshMorphTargetList;
- public
- constructor CreateOwned(aOwner: TgxMeshMorphTargetList);
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- property Owner: TgxMeshMorphTargetList read FOwner;
- end;
- // A list of TgxMeshMorphTarget objects.
- TgxMeshMorphTargetList = class(TgxPersistentObjectList)
- private
- FOwner: TPersistent;
- protected
- function GetMeshMorphTarget(Index: Integer): TgxMeshMorphTarget;
- public
- constructor CreateOwned(aOwner: TPersistent);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure Translate(const delta: TAffineVector);
- property Owner: TPersistent read FOwner;
- procedure Clear; override;
- property Items[Index: Integer]: TgxMeshMorphTarget read GetMeshMorphTarget; default;
- end;
- (* Mesh object with support for morph targets.
- The morph targets allow to change vertices and normals according to pre-
- existing "morph targets". *)
- TgxMorphableMeshObject = class(TgxMeshObject)
- private
- FMorphTargets: TgxMeshMorphTargetList;
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure Clear; override;
- procedure Translate(const delta: TAffineVector); override;
- procedure MorphTo(morphTargetIndex: Integer); virtual;
- procedure Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single); virtual;
- property MorphTargets: TgxMeshMorphTargetList read FMorphTargets;
- end;
- TgxVertexBoneWeight = packed record
- BoneID: Integer;
- weight: Single;
- end;
- TgxVertexBoneWeightArray = array [0 .. MaxInt div (2 * SizeOf(TgxVertexBoneWeight))] of TgxVertexBoneWeight;
- PgxVertexBoneWeightArray = ^TgxVertexBoneWeightArray;
- TgxVerticesBoneWeights = array [0 .. MaxInt div (2 * SizeOf(PgxVertexBoneWeightArray))] of PgxVertexBoneWeightArray;
- PgxVerticesBoneWeights = ^TgxVerticesBoneWeights;
- TgxVertexBoneWeightDynArray = array of TgxVertexBoneWeight;
- (* A mesh object with vertice bone attachments.
- The class adds per vertex bone weights to the standard morphable mesh.
- The TgxVertexBoneWeight structures are accessed via VerticesBonesWeights,
- they must be initialized by adjusting the BonesPerVertex and
- VerticeBoneWeightCount properties, you can also add vertex by vertex
- by using the AddWeightedBone method.
- When BonesPerVertex is 1, the weight is ignored (set to 1.0). *)
- TgxSkeletonMeshObject = class(TgxMorphableMeshObject)
- private
- FVerticesBonesWeights: PgxVerticesBoneWeights;
- FVerticeBoneWeightCount, FVerticeBoneWeightCapacity: Integer;
- FBonesPerVertex: Integer;
- FLastVerticeBoneWeightCount, FLastBonesPerVertex: Integer; // not persistent
- FBoneMatrixInvertedMeshes: TList; // not persistent
- FBackupInvertedMeshes: TList; // ragdoll
- procedure BackupBoneMatrixInvertedMeshes; // ragdoll
- procedure RestoreBoneMatrixInvertedMeshes; // ragdoll
- protected
- procedure SetVerticeBoneWeightCount(const val: Integer);
- procedure SetVerticeBoneWeightCapacity(const val: Integer);
- procedure SetBonesPerVertex(const val: Integer);
- procedure ResizeVerticesBonesWeights;
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure Clear; override;
- property VerticesBonesWeights: PgxVerticesBoneWeights read FVerticesBonesWeights;
- property VerticeBoneWeightCount: Integer read FVerticeBoneWeightCount write SetVerticeBoneWeightCount;
- property VerticeBoneWeightCapacity: Integer read FVerticeBoneWeightCapacity write SetVerticeBoneWeightCapacity;
- property BonesPerVertex: Integer read FBonesPerVertex write SetBonesPerVertex;
- function FindOrAdd(BoneID: Integer; const vertex, normal: TAffineVector): Integer; overload;
- function FindOrAdd(const boneIDs: TgxVertexBoneWeightDynArray; const vertex, normal: TAffineVector): Integer; overload;
- procedure AddWeightedBone(aBoneID: Integer; aWeight: Single);
- procedure AddWeightedBones(const boneIDs: TgxVertexBoneWeightDynArray);
- procedure PrepareBoneMatrixInvertedMeshes;
- procedure ApplyCurrentSkeletonFrame(normalize: Boolean);
- end;
- (* Describes a face group of a TgxMeshObject.
- Face groups should be understood as "a way to use mesh data to render
- a part or the whole mesh object".
- Subclasses implement the actual behaviours, and should have at least
- one "Add" method, taking in parameters all that is required to describe
- a single base facegroup element. *)
- TgxFaceGroup = class(TgxPersistentObject)
- private
- FOwner: TgxFaceGroups;
- FMaterialName: string;
- FMaterialCache: TgxLibMaterial;
- FLightMapIndex: Integer;
- FRenderGroupID: Integer;
- // NOT Persistent, internal use only (rendering options)
- protected
- procedure AttachLightmap(lightMap: TgxTexture; var mrci: TgxRenderContextInfo);
- procedure AttachOrDetachLightmap(var mrci: TgxRenderContextInfo);
- public
- constructor CreateOwned(aOwner: TgxFaceGroups); virtual;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure PrepareMaterialLibraryCache(matLib: TgxMaterialLibrary);
- procedure DropMaterialLibraryCache;
- procedure BuildList(var mrci: TgxRenderContextInfo); virtual; abstract;
- (* Add to the list the triangles corresponding to the facegroup.
- This function is used by TgxMeshObjects ExtractTriangles to retrieve
- all the triangles in a mesh. *)
- procedure AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil;
- aNormals: TgxAffineVectorList = nil); virtual;
- // Returns number of triangles in the facegroup.
- function TriangleCount: Integer; virtual; abstract;
- (* Reverses the rendering order of faces.
- Default implementation does nothing *)
- procedure Reverse; virtual;
- // Precalculate whatever is needed for rendering, called once
- procedure Prepare; virtual;
- property Owner: TgxFaceGroups read FOwner write FOwner;
- property MaterialName: string read FMaterialName write FMaterialName;
- property MaterialCache: TgxLibMaterial read FMaterialCache;
- // Index of lightmap in the lightmap library.
- property LightMapIndex: Integer read FLightMapIndex write FLightMapIndex;
- end;
- (* Known descriptions for face group mesh modes.
- - fgmmTriangles : issue all vertices with GL_TRIANGLES.
- - fgmmTriangleStrip : issue all vertices with GL_TRIANGLE_STRIP.
- - fgmmFlatTriangles : same as fgmmTriangles, but take advantage of having
- the same normal for all vertices of a triangle.
- - fgmmTriangleFan : issue all vertices with GL_TRIANGLE_FAN.
- - fgmmQuads : issue all vertices with GL_QUADS. *)
- TgxFaceGroupMeshMode = (fgmmTriangles, fgmmTriangleStrip, fgmmFlatTriangles, fgmmTriangleFan, fgmmQuads);
- (* A face group based on an indexlist.
- The index list refers to items in the mesh object (vertices, normals, etc.),
- that are all considered in sync, the render is obtained issueing the items
- in the order given by the vertices. *)
- TgxFGVertexIndexList = class(TgxFaceGroup)
- private
- FVertexIndices: TgxIntegerList;
- FIndexVBO: TgxVBOElementArrayHandle;
- FMode: TgxFaceGroupMeshMode;
- procedure SetupVBO;
- procedure InvalidateVBO;
- protected
- procedure SetVertexIndices(const val: TgxIntegerList);
- procedure AddToList(Source, destination: TgxAffineVectorList; indices: TgxIntegerList);
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure BuildList(var mrci: TgxRenderContextInfo); override;
- procedure AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil;
- aNormals: TgxAffineVectorList = nil); override;
- function TriangleCount: Integer; override;
- procedure Reverse; override;
- procedure Add(idx: Integer);
- procedure GetExtents(var min, max: TAffineVector);
- // If mode is strip or fan, convert the indices to triangle list indices.
- procedure ConvertToList;
- // Return the normal from the 1st three points in the facegroup
- function GetNormal: TAffineVector;
- property mode: TgxFaceGroupMeshMode read FMode write FMode;
- property vertexIndices: TgxIntegerList read FVertexIndices write SetVertexIndices;
- end;
- (* Adds normals and texcoords indices.
- Allows very compact description of a mesh. The Normals ad TexCoords
- indices are optionnal, if missing (empty), VertexIndices will be used. *)
- TFGVertexNormalTexIndexList = class(TgxFGVertexIndexList)
- private
- FNormalIndices: TgxIntegerList;
- FTexCoordIndices: TgxIntegerList;
- protected
- procedure SetNormalIndices(const val: TgxIntegerList);
- procedure SetTexCoordIndices(const val: TgxIntegerList);
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure BuildList(var mrci: TgxRenderContextInfo); override;
- procedure AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil;
- aNormals: TgxAffineVectorList = nil); override;
- procedure Add(vertexIdx, normalIdx, texCoordIdx: Integer);
- property normalIndices: TgxIntegerList read FNormalIndices write SetNormalIndices;
- property TexCoordIndices: TgxIntegerList read FTexCoordIndices write SetTexCoordIndices;
- end;
- (* Adds per index texture coordinates to its ancestor.
- Per index texture coordinates allows having different texture coordinates
- per triangle, depending on the face it is used in. *)
- TgxFGIndexTexCoordList = class(TgxFGVertexIndexList)
- private
- FTexCoords: TgxAffineVectorList;
- protected
- procedure SetTexCoords(const val: TgxAffineVectorList);
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TgxVirtualWriter); override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure BuildList(var mrci: TgxRenderContextInfo); override;
- procedure AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil;
- aNormals: TgxAffineVectorList = nil); override;
- procedure Add(idx: Integer; const texCoord: TAffineVector); overload;
- procedure Add(idx: Integer; const s, t: Single); overload;
- property texCoords: TgxAffineVectorList read FTexCoords write SetTexCoords;
- end;
- // A list of TgxFaceGroup objects.
- TgxFaceGroups = class(TgxPersistentObjectList)
- private
- FOwner: TgxMeshObject;
- protected
- function GetFaceGroup(Index: Integer): TgxFaceGroup;
- public
- constructor CreateOwned(aOwner: TgxMeshObject);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TgxVirtualReader); override;
- procedure PrepareMaterialLibraryCache(matLib: TgxMaterialLibrary);
- procedure DropMaterialLibraryCache;
- property Owner: TgxMeshObject read FOwner;
- procedure Clear; override;
- property Items[Index: Integer]: TgxFaceGroup read GetFaceGroup; default;
- procedure AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil; aNormals: TgxAffineVectorList = nil);
- // Material Library of the owner TgxBaseMesh.
- function MaterialLibrary: TgxMaterialLibrary;
- (* Sort faces by material.
- Those without material first in list, followed by opaque materials,
- then transparent materials. *)
- procedure SortByMaterial;
- end;
- (* Determines how normals orientation is defined in a mesh.
- - mnoDefault : uses default orientation
- - mnoInvert : inverse of default orientation
- - mnoAutoSolid : autocalculate to make the mesh globally solid
- - mnoAutoHollow : autocalculate to make the mesh globally hollow *)
- TgxMeshNormalsOrientation = (mnoDefault, mnoInvert); // , mnoAutoSolid, mnoAutoHollow);
- (* Abstract base class for different vector file Formatx.
- The actual implementation for these files (3DS, DXF..) must be done
- seperately. The concept for TgxVectorFile is very similar to TGraphic
- (see Delphi Help). *)
- TgxVectorFile = class(TgxDataFile)
- private
- FNormalsOrientation: TgxMeshNormalsOrientation;
- protected
- procedure SetNormalsOrientation(const val: TgxMeshNormalsOrientation); virtual;
- public
- constructor Create(aOwner: TPersistent); override;
- function Owner: TgxBaseMesh;
- property NormalsOrientation: TgxMeshNormalsOrientation read FNormalsOrientation write SetNormalsOrientation;
- end;
- TgxVectorFileClass = class of TgxVectorFile;
- (* GLSM ( GXScene Mesh) vector file.
- This corresponds to the 'native' Scene format, and object persistence
- stream, which should be the 'fastest' of all formats to load, and supports
- all of GXScene features. *)
- TgxVectorFileGLSM = class(TgxVectorFile)
- public
- class function Capabilities: TDataFileCapabilities; override;
- procedure LoadFromStream(aStream: TStream); override;
- procedure SaveToStream(aStream: TStream); override;
- end;
- // Base class for mesh objects.
- TgxBaseMesh = class(TgxSceneObject)
- private
- FNormalsOrientation: TgxMeshNormalsOrientation;
- FMaterialLibrary: TgxMaterialLibrary;
- FLightmapLibrary: TgxMaterialLibrary;
- FAxisAlignedDimensionsCache: TVector4f;
- FBaryCenterOffsetChanged: Boolean;
- FBaryCenterOffset: TVector4f;
- FUseMeshMaterials: Boolean;
- FOverlaySkeleton: Boolean;
- FIgnoreMissingTextures: Boolean;
- FAutoCentering: TgxMeshAutoCenterings;
- FAutoScaling: TgxCoordinates;
- FMaterialLibraryCachesPrepared: Boolean;
- FConnectivity: TObject;
- FLastLoadedFilename: string;
- protected
- FMeshObjects: TgxMeshObjectList; // a list of mesh objects
- FSkeleton: TgxSkeleton; // skeleton data & frames
- procedure SetUseMeshMaterials(const val: Boolean);
- procedure SetMaterialLibrary(const val: TgxMaterialLibrary);
- procedure SetLightmapLibrary(const val: TgxMaterialLibrary);
- procedure SetNormalsOrientation(const val: TgxMeshNormalsOrientation);
- procedure SetOverlaySkeleton(const val: Boolean);
- procedure SetAutoScaling(const Value: TgxCoordinates);
- procedure DestroyHandle; override;
- (* Invoked after creating a TgxVectorFile and before loading.
- Triggered by LoadFromFile/Stream and AddDataFromFile/Stream.
- Allows to adjust/transfer subclass-specific features. *)
- procedure PrepareVectorFile(aFile: TgxVectorFile); virtual;
- (* Invoked after a mesh has been loaded/added.
- Triggered by LoadFromFile/Stream and AddDataFromFile/Stream.
- Allows to adjust/transfer subclass-specific features. *)
- procedure PrepareMesh; virtual;
- (* Recursively propagated to mesh object and facegroups.
- Notifies that they all can establish their material library caches. *)
- procedure PrepareMaterialLibraryCache;
- (* Recursively propagated to mesh object and facegroups.
- Notifies that they all should forget their material library caches. *)
- procedure DropMaterialLibraryCache;
- (* Prepare the texture and materials before rendering.
- Invoked once, before building the list and NOT while building the list,
- MaterialLibraryCache can be assumed to having been prepared if materials
- are active. Default behaviour is to prepare build lists for the
- meshobjects. *)
- procedure PrepareBuildList(var mrci: TgxRenderContextInfo); virtual;
- public
- constructor Create(aOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- function AxisAlignedDimensionsUnscaled: TVector4f; override;
- function BarycenterOffset: TVector4f;
- function BarycenterPosition: TVector4f;
- function BarycenterAbsolutePosition: TVector4f; override;
- procedure BuildList(var rci: TgxRenderContextInfo); override;
- procedure DoRender(var rci: TgxRenderContextInfo; renderSelf, renderChildren: Boolean); override;
- procedure StructureChanged; override;
- (* Notifies that geometry data changed, but no re-preparation is needed.
- Using this method will usually be faster, but may result in incorrect
- rendering, reduced performance and/or invalid bounding box data
- (ie. invalid collision detection). Use with caution. *)
- procedure StructureChangedNoPrepare;
- // BEWARE! Utterly inefficient implementation!
- function RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil)
- : Boolean; override;
- function GenerateSilhouette(const SilhouetteParameters: TgxSilhouetteParameters): TgxSilhouette; override;
- (* This method allows fast shadow volumes for GLActors.
- If your actor/mesh doesn't change, you don't need to call this.
- It basically caches the connectivity data. *)
- procedure BuildSilhouetteConnectivityData;
- property MeshObjects: TgxMeshObjectList read FMeshObjects;
- property Skeleton: TgxSkeleton read FSkeleton;
- // Computes the extents of the mesh.
- procedure GetExtents(out min, max: TAffineVector);
- // Computes the barycenter of the mesh.
- function GetBarycenter: TAffineVector;
- (* Invoked after a mesh has been loaded.
- Should auto-center according to the AutoCentering property. *)
- procedure PerformAutoCentering; virtual;
- (* Invoked after a mesh has been loaded.
- Should auto-scale the vertices of the meshobjects to AutoScaling the property. *)
- procedure PerformAutoScaling; virtual;
- (* Loads a vector file.
- A vector files (for instance a ".3DS") stores the definition of
- a mesh as well as materials property.
- Loading a file replaces the current one (if any). *)
- procedure LoadFromFile(const filename: string); virtual;
- (* Loads a vector file from a stream.
- See LoadFromFile.
- The filename attribute is required to identify the type data you're
- streaming (3DS, OBJ, etc.) *)
- procedure LoadFromStream(const filename: string; aStream: TStream); virtual;
- (* Saves to a vector file.
- Note that only some of the vector files formats can be written. *)
- procedure SaveToFile(const filename: string); virtual;
- (* Saves to a vector file in a stream.
- Note that only some of the vector files formats can be written. *)
- procedure SaveToStream(const filename: string; aStream: TStream); virtual;
- (* Loads additionnal data from a file.
- Additionnal data could be more animation frames or morph target.
- The VectorFile importer must be able to handle addition of data
- flawlessly. *)
- procedure AddDataFromFile(const filename: string); virtual;
- // Loads additionnal data from stream. See AddDataFromFile.
- procedure AddDataFromStream(const filename: string; aStream: TStream); virtual;
- (* Returns the filename of the last loaded file, or a blank string if not
- file was loaded (or if the mesh was dinamically built). This does not
- take into account the data added to the mesh (through AddDataFromFile)
- or saved files. *)
- function LastLoadedFilename: string;
- (* Determines if a mesh should be centered and how.
- AutoCentering is performed only after loading a mesh, it has
- no effect on already loaded mesh data or when adding from a file/stream.
- If you want to alter mesh data, use direct manipulation methods
- (on the TgxMeshObjects). *)
- property AutoCentering: TgxMeshAutoCenterings read FAutoCentering write FAutoCentering default [];
- (* Scales vertices to a AutoScaling.
- AutoScaling is performed only after loading a mesh, it has
- no effect on already loaded mesh data or when adding from a file/stream.
- If you want to alter mesh data, use direct manipulation methods
- (on the TgxMeshObjects). *)
- property AutoScaling: TgxCoordinates read FAutoScaling write FAutoScaling;
- (* Material library where mesh materials will be stored/retrieved.
- If this property is not defined or if UseMeshMaterials is false,
- only the FreeForm's material will be used (and the mesh's materials
- will be ignored. *)
- property MaterialLibrary: TgxMaterialLibrary read FMaterialLibrary write SetMaterialLibrary;
- (* Defines wether materials declared in the vector file mesh are used.
- You must also define the MaterialLibrary property. *)
- property UseMeshMaterials: Boolean read FUseMeshMaterials write SetUseMeshMaterials default True;
- (* LightMap library where lightmaps will be stored/retrieved.
- If this property is not defined, lightmaps won't be used.
- Lightmaps currently *always* use the second texture unit (unit 1),
- and may interfere with multi-texture materials. *)
- property LightmapLibrary: TgxMaterialLibrary read FLightmapLibrary write SetLightmapLibrary;
- (* If True, exceptions about missing textures will be ignored.
- Implementation is up to the file loader class (ie. this property
- may be ignored by some loaders) *)
- property IgnoreMissingTextures: Boolean read FIgnoreMissingTextures write FIgnoreMissingTextures default False;
- // Normals orientation for owned mesh.
- property NormalsOrientation: TgxMeshNormalsOrientation read FNormalsOrientation write SetNormalsOrientation
- default mnoDefault;
- // Request rendering of skeleton bones over the mesh.
- property OverlaySkeleton: Boolean read FOverlaySkeleton write SetOverlaySkeleton default False;
- end;
- (* Container objects for a vector file mesh.
- FreeForms allows loading and rendering vector files (like 3DStudio
- ".3DS" file) in GLScene. Meshes can be loaded with the LoadFromFile
- method.
- A FreeForm may contain more than one mesh, but they will all be handled
- as a single object in a scene. *)
- TgxFreeForm = class(TgxBaseMesh)
- private
- FOctree: TgxOctree;
- protected
- function GetOctree: TgxOctree;
- public
- constructor Create(aOwner: TComponent); override;
- destructor Destroy; override;
- function OctreeRayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
- intersectNormal: PVector4f = nil): Boolean;
- function OctreeSphereSweepIntersect(const rayStart, rayVector: TVector4f; const velocity, radius: Single;
- intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil): Boolean;
- function OctreeTriangleIntersect(const v1, v2, v3: TAffineVector): Boolean;
- (* Returns true if Point is inside the free form - this will only work
- properly on closed meshes. Requires that Octree has been prepared. *)
- function OctreePointInMesh(const Point: TVector4f): Boolean;
- function OctreeAABBIntersect(const aabb: TAABB; objMatrix, invObjMatrix: TMatrix4f;
- triangles: TgxAffineVectorList = nil): Boolean;
- // TODO: function OctreeSphereIntersect
- (* Octree support *experimental*.
- Use only if you understand what you're doing! *)
- property Octree: TgxOctree read GetOctree;
- procedure BuildOctree(TreeDepth: Integer = 3);
- published
- property AutoCentering;
- property AutoScaling;
- property MaterialLibrary;
- property LightmapLibrary;
- property UseMeshMaterials;
- property NormalsOrientation;
- end;
- (* Miscellanious actor options.
- aoSkeletonNormalizeNormals : if set the normals of a skeleton-animated
- mesh will be normalized, this is not required if no normals-based texture
- coordinates generation occurs, and thus may be unset to improve performance. *)
- TgxActorOption = (aoSkeletonNormalizeNormals);
- TgxActorOptions = set of TgxActorOption;
- const
- cDefaultActorOptions = [aoSkeletonNormalizeNormals];
- type
- TgxActor = class;
- TgxActorAnimationReference = (aarMorph, aarSkeleton, aarNone);
- (* An actor animation sequence.
- An animation sequence is a named set of contiguous frames that can be used
- for animating an actor. The referred frames can be either morph or skeletal
- frames (choose which via the Reference property).
- An animation can be directly "played" by the actor by selecting it with
- SwitchAnimation, and can also be "blended" via a TgxAnimationControler. *)
- TgxActorAnimation = class(TCollectionItem)
- private
- FName: string;
- FStartFrame: Integer;
- FEndFrame: Integer;
- FReference: TgxActorAnimationReference;
- protected
- function GetDisplayName: string; override;
- function FrameCount: Integer;
- procedure SetStartFrame(const val: Integer);
- procedure SetEndFrame(const val: Integer);
- procedure SetReference(val: TgxActorAnimationReference);
- procedure SetAsString(const val: string);
- function GetAsString: string;
- public
- constructor Create(Collection: TCollection); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- property AsString: string read GetAsString write SetAsString;
- function OwnerActor: TgxActor;
- (* Linearly removes the translation component between skeletal frames.
- This function will compute the translation of the first bone (index 0)
- and linearly subtract this translation in all frames between startFrame
- and endFrame. Its purpose is essentially to remove the 'slide' that
- exists in some animation formats (f.i. SMD). *)
- procedure MakeSkeletalTranslationStatic;
- (* Removes the absolute rotation component of the skeletal frames.
- Some formats will store frames with absolute rotation information,
- if this correct if the animation is the "main" animation.
- This function removes that absolute information, making the animation
- frames suitable for blending purposes. *)
- procedure MakeSkeletalRotationDelta;
- published
- property Name: string read FName write FName;
- // Index of the initial frame of the animation.
- property startFrame: Integer read FStartFrame write SetStartFrame;
- // Index of the final frame of the animation.
- property endFrame: Integer read FEndFrame write SetEndFrame;
- // Indicates if this is a skeletal or a morph-based animation.
- property reference: TgxActorAnimationReference read FReference write SetReference default aarMorph;
- end;
- TgxActorAnimationName = string;
- // Collection of actor animations sequences.
- TgxActorAnimations = class(TCollection)
- private
- FOwner: TgxActor;
- protected
- function GetOwner: TPersistent; override;
- procedure SetItems(Index: Integer; const val: TgxActorAnimation);
- function GetItems(Index: Integer): TgxActorAnimation;
- public
- constructor Create(aOwner: TgxActor);
- function Add: TgxActorAnimation;
- function FindItemID(ID: Integer): TgxActorAnimation;
- function FindName(const aName: string): TgxActorAnimation;
- function FindFrame(aFrame: Integer; aReference: TgxActorAnimationReference): TgxActorAnimation;
- procedure SetToStrings(aStrings: TStrings);
- procedure SaveToStream(aStream: TStream);
- procedure LoadFromStream(aStream: TStream);
- procedure SaveToFile(const filename: string);
- procedure LoadFromFile(const filename: string);
- property Items[index: Integer]: TgxActorAnimation read GetItems write SetItems; default;
- function Last: TgxActorAnimation;
- end;
- // Base class for skeletal animation control.
- TgxBaseAnimationControler = class(TComponent)
- private
- FEnabled: Boolean;
- FActor: TgxActor;
- protected
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure SetEnabled(const val: Boolean);
- procedure SetActor(const val: TgxActor);
- procedure DoChange; virtual;
- function Apply(var lerpInfo: TGXBlendedLerpInfo): Boolean; virtual;
- public
- constructor Create(aOwner: TComponent); override;
- destructor Destroy; override;
- published
- property Enabled: Boolean read FEnabled write SetEnabled default True;
- property Actor: TgxActor read FActor write SetActor;
- end;
- (* Controls the blending of an additionnal skeletal animation into an actor.
- The animation controler allows animating an actor with several animations
- at a time, for instance, you could use a "run" animation as base animation
- (in TgxActor), blend an animation that makes the arms move differently
- depending on what the actor is carrying, along with an animation that will
- make the head turn toward a target. *)
- TgxAnimationControler = class(TgxBaseAnimationControler)
- private
- FAnimationName: TgxActorAnimationName;
- FRatio: Single;
- protected
- procedure SetAnimationName(const val: TgxActorAnimationName);
- procedure SetRatio(const val: Single);
- procedure DoChange; override;
- function Apply(var lerpInfo: TGXBlendedLerpInfo): Boolean; override;
- published
- property AnimationName: string read FAnimationName write SetAnimationName;
- property Ratio: Single read FRatio write SetRatio;
- end;
- (* Actor frame-interpolation mode.
- - afpNone : no interpolation, display CurrentFrame only
- - afpLinear : perform linear interpolation between current and next frame *)
- TgxActorFrameInterpolation = (afpNone, afpLinear);
- (* Defines how an actor plays between its StartFrame and EndFrame.
- aamNone : no animation is performed
- aamPlayOnce : play from current frame to EndFrame, once end frame has
- been reached, switches to aamNone
- aamLoop : play from current frame to EndFrame, once end frame has
- been reached, sets CurrentFrame to StartFrame
- aamBounceForward : play from current frame to EndFrame, once end frame
- has been reached, switches to aamBounceBackward
- aamBounceBackward : play from current frame to StartFrame, once start
- frame has been reached, switches to aamBounceForward
- aamExternal : Allows for external animation control *)
- TgxActorAnimationMode = (aamNone, aamPlayOnce, aamLoop, aamBounceForward, aamBounceBackward, aamLoopBackward, aamExternal);
- (* Mesh class specialized in animated meshes.
- The TgxActor provides a quick interface to animated meshes based on morph
- or skeleton frames, it is capable of performing frame interpolation and
- animation blending (via TgxAnimationControler components). *)
- TgxActor = class(TgxBaseMesh)
- private
- FStartFrame, FEndFrame: Integer;
- FReference: TgxActorAnimationReference;
- FCurrentFrame: Integer;
- FCurrentFrameDelta: Single;
- FFrameInterpolation: TgxActorFrameInterpolation;
- FInterval: Integer;
- FAnimationMode: TgxActorAnimationMode;
- FOnFrameChanged: TNotifyEvent;
- FOnEndFrameReached, FOnStartFrameReached: TNotifyEvent;
- FAnimations: TgxActorAnimations;
- FTargetSmoothAnimation: TgxActorAnimation;
- FControlers: TList;
- FOptions: TgxActorOptions;
- protected
- procedure SetCurrentFrame(val: Integer);
- procedure SetStartFrame(val: Integer);
- procedure SetEndFrame(val: Integer);
- procedure SetReference(val: TgxActorAnimationReference);
- procedure SetAnimations(const val: TgxActorAnimations);
- function StoreAnimations: Boolean;
- procedure SetOptions(const val: TgxActorOptions);
- procedure PrepareMesh; override;
- procedure PrepareBuildList(var mrci: TgxRenderContextInfo); override;
- procedure DoAnimate; virtual;
- procedure RegisterControler(aControler: TgxBaseAnimationControler);
- procedure UnRegisterControler(aControler: TgxBaseAnimationControler);
- public
- constructor Create(aOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure BuildList(var rci: TgxRenderContextInfo); override;
- procedure DoProgress(const progressTime: TgxProgressTimes); override;
- procedure LoadFromStream(const filename: string; aStream: TStream); override;
- procedure SwitchToAnimation(anAnimation: TgxActorAnimation; smooth: Boolean = False); overload;
- procedure SwitchToAnimation(const AnimationName: string; smooth: Boolean = False); overload;
- procedure SwitchToAnimation(animationIndex: Integer; smooth: Boolean = False); overload;
- function CurrentAnimation: string;
- (* Synchronize self animation with an other actor.
- Copies Start/Current/End Frame values, CurrentFrameDelta,
- AnimationMode and FrameInterpolation. *)
- procedure Synchronize(referenceActor: TgxActor);
- (* Provides a direct access to FCurrentFrame without any checks.
- Used in TgxActorProxy. *)
- procedure SetCurrentFrameDirect(const Value: Integer);
- function NextFrameIndex: Integer;
- procedure NextFrame(nbSteps: Integer = 1);
- procedure PrevFrame(nbSteps: Integer = 1);
- function FrameCount: Integer;
- (* Indicates whether the actor is currently swithing animations (with
- smooth interpolation). *)
- function isSwitchingAnimation: Boolean;
- published
- property startFrame: Integer read FStartFrame write SetStartFrame default 0;
- property endFrame: Integer read FEndFrame write SetEndFrame default 0;
- (* Reference Frame Animation mode.
- Allows specifying if the model is primarily morph or skeleton based. *)
- property reference: TgxActorAnimationReference read FReference write FReference default aarMorph;
- // Current animation frame.
- property CurrentFrame: Integer read FCurrentFrame write SetCurrentFrame default 0;
- // Value in the [0; 1] range expressing the delta to the next frame.
- property CurrentFrameDelta: Single read FCurrentFrameDelta write FCurrentFrameDelta;
- // Frame interpolation mode (afpNone/afpLinear).
- property FrameInterpolation: TgxActorFrameInterpolation read FFrameInterpolation write FFrameInterpolation default afpLinear;
- // See TgxActorAnimationMode.
- property AnimationMode: TgxActorAnimationMode read FAnimationMode write FAnimationMode default aamNone;
- // Interval between frames, in milliseconds.
- property Interval: Integer read FInterval write FInterval;
- // Actor and animation miscellanious options.
- property Options: TgxActorOptions read FOptions write SetOptions default cDefaultActorOptions;
- // Triggered after each CurrentFrame change.
- property OnFrameChanged: TNotifyEvent read FOnFrameChanged write FOnFrameChanged;
- // Triggered after EndFrame has been reached by progression or "nextframe"
- property OnEndFrameReached: TNotifyEvent read FOnEndFrameReached write FOnEndFrameReached;
- // Triggered after StartFrame has been reached by progression or "nextframe"
- property OnStartFrameReached: TNotifyEvent read FOnStartFrameReached write FOnStartFrameReached;
- // Collection of animations sequences.
- property Animations: TgxActorAnimations read FAnimations write SetAnimations stored StoreAnimations;
- property AutoCentering;
- property MaterialLibrary;
- property LightmapLibrary;
- property UseMeshMaterials;
- property NormalsOrientation;
- property OverlaySkeleton;
- end;
- TgxVectorFileFormat = class
- public
- VectorFileClass: TgxVectorFileClass;
- Extension: string;
- Description: string;
- DescResID: Integer;
- end;
- // Stores registered vector file Formatx.
- TgxVectorFileFormatsList = class(TgxPersistentObjectList)
- public
- destructor Destroy; override;
- procedure Add(const Ext, Desc: string; DescID: Integer; AClass: TgxVectorFileClass);
- function FindExt(Ext: string): TgxVectorFileClass;
- function FindFromFileName(const filename: string): TgxVectorFileClass;
- procedure Remove(AClass: TgxVectorFileClass);
- procedure BuildFilterStrings(VectorFileClass: TgxVectorFileClass; out descriptions, filters: string;
- formatsThatCanBeOpened: Boolean = True; formatsThatCanBeSaved: Boolean = False);
- function FindExtByIndex(Index: Integer; formatsThatCanBeOpened: Boolean = True;
- formatsThatCanBeSaved: Boolean = False): string;
- end;
- EgxInvalidVectorFile = class(Exception);
- // Read access to the list of registered vector file formats
- function GetVectorFileFormats: TgxVectorFileFormatsList;
- // A file extension filter suitable for dialog's 'Filter' property
- function VectorFileFormatsFilter: string;
- // A file extension filter suitable for a savedialog's 'Filter' property
- function VectorFileFormatsSaveFilter: string;
- (* Returns an extension by its index in the vector files dialogs filter.
- Use VectorFileFormatsFilter to obtain the filter. *)
- function VectorFileFormatExtensionByIndex(Index: Integer): string;
- procedure RegisterVectorFileFormat(const aExtension, aDescription: string; AClass: TgxVectorFileClass);
- procedure UnregisterVectorFileClass(AClass: TgxVectorFileClass);
- var
- vVectorFileObjectsAllocateMaterials: Boolean = True;
- // Flag to avoid loading materials (useful for IDE Extentions or scene editors)
- vVectorFileObjectsEnableVBOByDefault: Boolean = True;
- implementation //--------------------------------------------------------------
- uses
- GXS.BaseMeshSilhouette;
- var
- vVectorFileFormats: TgxVectorFileFormatsList;
- vNextRenderGroupID: Integer = 1;
- const
- cAAFHeader: AnsiString = 'AAF';
- function GetVectorFileFormats: TgxVectorFileFormatsList;
- begin
- if not Assigned(vVectorFileFormats) then
- vVectorFileFormats := TgxVectorFileFormatsList.Create;
- Result := vVectorFileFormats;
- end;
- function VectorFileFormatsFilter: string;
- var
- f: string;
- begin
- GetVectorFileFormats.BuildFilterStrings(TgxVectorFile, Result, f);
- end;
- function VectorFileFormatsSaveFilter: string;
- var
- f: string;
- begin
- GetVectorFileFormats.BuildFilterStrings(TgxVectorFile, Result, f, False, True);
- end;
- procedure RegisterVectorFileFormat(const aExtension, aDescription: string; AClass: TgxVectorFileClass);
- begin
- RegisterClass(AClass);
- GetVectorFileFormats.Add(aExtension, aDescription, 0, AClass);
- end;
- procedure UnregisterVectorFileClass(AClass: TgxVectorFileClass);
- begin
- if Assigned(vVectorFileFormats) then
- vVectorFileFormats.Remove(AClass);
- end;
- function VectorFileFormatExtensionByIndex(Index: Integer): string;
- begin
- Result := GetVectorFileFormats.FindExtByIndex(index);
- end;
- destructor TgxVectorFileFormatsList.Destroy;
- begin
- Clean;
- inherited;
- end;
- procedure TgxVectorFileFormatsList.Add(const Ext, Desc: string; DescID: Integer; AClass: TgxVectorFileClass);
- var
- newRec: TgxVectorFileFormat;
- begin
- newRec := TgxVectorFileFormat.Create;
- with newRec do
- begin
- Extension := AnsiLowerCase(Ext);
- VectorFileClass := AClass;
- Description := Desc;
- DescResID := DescID;
- end;
- inherited Add(newRec);
- end;
- function TgxVectorFileFormatsList.FindExt(Ext: string): TgxVectorFileClass;
- var
- i: Integer;
- begin
- Ext := AnsiLowerCase(Ext);
- for i := Count - 1 downto 0 do
- with TgxVectorFileFormat(Items[i]) do
- begin
- if Extension = Ext then
- begin
- Result := VectorFileClass;
- Exit;
- end;
- end;
- Result := nil;
- end;
- function TgxVectorFileFormatsList.FindFromFileName(const filename: string): TgxVectorFileClass;
- var
- Ext: string;
- begin
- Ext := ExtractFileExt(filename);
- System.Delete(Ext, 1, 1);
- Result := FindExt(Ext);
- if not Assigned(Result) then
- raise EgxInvalidVectorFile.CreateFmt(strUnknownExtension, [Ext, 'GLFile' + UpperCase(Ext)]);
- end;
- procedure TgxVectorFileFormatsList.Remove(AClass: TgxVectorFileClass);
- var
- i: Integer;
- begin
- for i := Count - 1 downto 0 do
- begin
- if TgxVectorFileFormat(Items[i]).VectorFileClass.InheritsFrom(AClass) then
- DeleteAndFree(i);
- end;
- end;
- procedure TgxVectorFileFormatsList.BuildFilterStrings(VectorFileClass: TgxVectorFileClass; out descriptions, filters: string;
- formatsThatCanBeOpened: Boolean = True; formatsThatCanBeSaved: Boolean = False);
- var
- k, i: Integer;
- p: TgxVectorFileFormat;
- begin
- descriptions := '';
- filters := '';
- k := 0;
- for i := 0 to Count - 1 do
- begin
- p := TgxVectorFileFormat(Items[i]);
- if p.VectorFileClass.InheritsFrom(VectorFileClass) and (p.Extension <> '') and
- ((formatsThatCanBeOpened and (dfcRead in p.VectorFileClass.Capabilities)) or
- (formatsThatCanBeSaved and (dfcWrite in p.VectorFileClass.Capabilities))) then
- begin
- with p do
- begin
- if k <> 0 then
- begin
- descriptions := descriptions + '|';
- filters := filters + ';';
- end;
- if (Description = '') and (DescResID <> 0) then
- Description := LoadStr(DescResID);
- FmtStr(descriptions, '%s%s (*.%s)|*.%2:s', [descriptions, Description, Extension]);
- filters := filters + '*.' + Extension;
- Inc(k);
- end;
- end;
- end;
- if (k > 1) and (not formatsThatCanBeSaved) then
- FmtStr(descriptions, '%s (%s)|%1:s|%s', [sAllFilter, filters, descriptions]);
- end;
- function TgxVectorFileFormatsList.FindExtByIndex(Index: Integer; formatsThatCanBeOpened: Boolean = True;
- formatsThatCanBeSaved: Boolean = False): string;
- var
- i: Integer;
- p: TgxVectorFileFormat;
- begin
- Result := '';
- if index > 0 then
- begin
- for i := 0 to Count - 1 do
- begin
- p := TgxVectorFileFormat(Items[i]);
- if (formatsThatCanBeOpened and (dfcRead in p.VectorFileClass.Capabilities)) or
- (formatsThatCanBeSaved and (dfcWrite in p.VectorFileClass.Capabilities)) then
- begin
- if index = 1 then
- begin
- Result := p.Extension;
- Break;
- end
- else
- Dec(index);
- end;
- end;
- end;
- end;
- // ------------------
- // ------------------ TgxBaseMeshObject ------------------
- // ------------------
- constructor TgxBaseMeshObject.Create;
- begin
- FVertices := TgxAffineVectorList.Create;
- FNormals := TgxAffineVectorList.Create;
- FVisible := True;
- inherited Create;
- end;
- destructor TgxBaseMeshObject.Destroy;
- begin
- FNormals.Free;
- FVertices.Free;
- inherited;
- end;
- procedure TgxBaseMeshObject.Assign(Source: TPersistent);
- begin
- if Source is TgxBaseMeshObject then
- begin
- FName := TgxBaseMeshObject(Source).Name;
- FVertices.Assign(TgxBaseMeshObject(Source).FVertices);
- FNormals.Assign(TgxBaseMeshObject(Source).FNormals);
- end
- else
- inherited; // Die!
- end;
- procedure TgxBaseMeshObject.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(1); // Archive Version 1, added FVisible
- WriteString(FName);
- FVertices.WriteToFiler(writer);
- FNormals.WriteToFiler(writer);
- WriteBoolean(FVisible);
- end;
- end;
- procedure TgxBaseMeshObject.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion in [0 .. 1] then
- with reader do
- begin
- FName := ReadString;
- FVertices.ReadFromFiler(reader);
- FNormals.ReadFromFiler(reader);
- if archiveVersion >= 1 then
- FVisible := ReadBoolean
- else
- FVisible := True;
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TgxBaseMeshObject.Clear;
- begin
- FNormals.Clear;
- FVertices.Clear;
- end;
- procedure TgxBaseMeshObject.ContributeToBarycenter(var currentSum: TAffineVector; var nb: Integer);
- begin
- AddVector(currentSum, FVertices.Sum);
- nb := nb + FVertices.Count;
- end;
- procedure TgxBaseMeshObject.Translate(const delta: TAffineVector);
- begin
- FVertices.Translate(delta);
- end;
- procedure TgxBaseMeshObject.BuildNormals(vertexIndices: TgxIntegerList; mode: TgxMeshObjectMode;
- normalIndices: TgxIntegerList = nil);
- var
- i, base: Integer;
- n: TAffineVector;
- newNormals: TgxIntegerList;
- function TranslateNewNormal(vertexIndex: Integer; const delta: TAffineVector): Integer;
- var
- pv: PAffineVector;
- begin
- Result := newNormals[vertexIndex];
- if Result < base then
- begin
- Result := normals.Add(NullVector);
- newNormals[vertexIndex] := Result;
- end;
- pv := @normals.list[Result];
- AddVector(pv^, delta);
- end;
- begin
- if not Assigned(normalIndices) then
- begin
- // build bijection
- normals.Clear;
- normals.Count := Vertices.Count;
- case mode of
- momTriangles:
- begin
- i := 0;
- while i <= vertexIndices.Count - 3 do
- with normals do
- begin
- with Vertices do
- begin
- CalcPlaneNormal(Items[vertexIndices[i + 0]], Items[vertexIndices[i + 1]], Items[vertexIndices[i + 2]], n);
- end;
- with normals do
- begin
- TranslateItem(vertexIndices[i + 0], n);
- TranslateItem(vertexIndices[i + 1], n);
- TranslateItem(vertexIndices[i + 2], n);
- end;
- Inc(i, 3);
- end;
- end;
- momTriangleStrip:
- begin
- i := 0;
- while i <= vertexIndices.Count - 3 do
- with normals do
- begin
- with Vertices do
- begin
- if (i and 1) = 0 then
- CalcPlaneNormal(Items[vertexIndices[i + 0]], Items[vertexIndices[i + 1]], Items[vertexIndices[i + 2]], n)
- else
- CalcPlaneNormal(Items[vertexIndices[i + 0]], Items[vertexIndices[i + 2]], Items[vertexIndices[i + 1]], n);
- end;
- with normals do
- begin
- TranslateItem(vertexIndices[i + 0], n);
- TranslateItem(vertexIndices[i + 1], n);
- TranslateItem(vertexIndices[i + 2], n);
- end;
- Inc(i, 1);
- end;
- end;
- else
- Assert(False);
- end;
- normals.normalize;
- end
- else
- begin
- // add new normals
- base := normals.Count;
- newNormals := TgxIntegerList.Create;
- newNormals.AddSerie(-1, 0, Vertices.Count);
- case mode of
- momTriangles:
- begin
- i := 0;
- while i <= vertexIndices.Count - 3 do
- begin
- with Vertices do
- begin
- CalcPlaneNormal(Items[vertexIndices[i + 0]], Items[vertexIndices[i + 1]], Items[vertexIndices[i + 2]], n);
- end;
- normalIndices.Add(TranslateNewNormal(vertexIndices[i + 0], n));
- normalIndices.Add(TranslateNewNormal(vertexIndices[i + 1], n));
- normalIndices.Add(TranslateNewNormal(vertexIndices[i + 2], n));
- Inc(i, 3);
- end;
- end;
- momTriangleStrip:
- begin
- i := 0;
- while i <= vertexIndices.Count - 3 do
- begin
- with Vertices do
- begin
- if (i and 1) = 0 then
- CalcPlaneNormal(Items[vertexIndices[i + 0]], Items[vertexIndices[i + 1]], Items[vertexIndices[i + 2]], n)
- else
- CalcPlaneNormal(Items[vertexIndices[i + 0]], Items[vertexIndices[i + 2]], Items[vertexIndices[i + 1]], n);
- end;
- normalIndices.Add(TranslateNewNormal(vertexIndices[i + 0], n));
- normalIndices.Add(TranslateNewNormal(vertexIndices[i + 1], n));
- normalIndices.Add(TranslateNewNormal(vertexIndices[i + 2], n));
- Inc(i, 1);
- end;
- end;
- else
- Assert(False);
- end;
- for i := base to normals.Count - 1 do
- NormalizeVector(normals.list^[i]);
- newNormals.Free;
- end;
- end;
- function TgxBaseMeshObject.ExtractTriangles(texCoords: TgxAffineVectorList = nil; normals: TgxAffineVectorList = nil)
- : TgxAffineVectorList;
- begin
- Result := TgxAffineVectorList.Create;
- if (Vertices.Count mod 3) = 0 then
- begin
- Result.Assign(Vertices);
- if Assigned(normals) then
- normals.Assign(Self.normals);
- end;
- end;
- procedure TgxBaseMeshObject.SetVertices(const val: TgxAffineVectorList);
- begin
- FVertices.Assign(val);
- end;
- procedure TgxBaseMeshObject.SetNormals(const val: TgxAffineVectorList);
- begin
- FNormals.Assign(val);
- end;
- // ------------------
- // ------------------ TgxSkeletonFrame ------------------
- // ------------------
- constructor TgxSkeletonFrame.CreateOwned(aOwner: TgxSkeletonFrameList);
- begin
- FOwner := aOwner;
- aOwner.Add(Self);
- Create;
- end;
- constructor TgxSkeletonFrame.Create;
- begin
- inherited Create;
- FPosition := TgxAffineVectorList.Create;
- FRotation := TgxAffineVectorList.Create;
- FQuaternion := TgxQuaternionList.Create;
- FTransformMode := sftRotation;
- end;
- destructor TgxSkeletonFrame.Destroy;
- begin
- FlushLocalMatrixList;
- FRotation.Free;
- FPosition.Free;
- FQuaternion.Free;
- inherited Destroy;
- end;
- procedure TgxSkeletonFrame.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(1); // Archive Version 1
- WriteString(FName);
- FPosition.WriteToFiler(writer);
- FRotation.WriteToFiler(writer);
- FQuaternion.WriteToFiler(writer);
- WriteInteger(Integer(FTransformMode));
- end;
- end;
- procedure TgxSkeletonFrame.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if (archiveVersion = 0) or (archiveVersion = 1) then
- with reader do
- begin
- FName := ReadString;
- FPosition.ReadFromFiler(reader);
- FRotation.ReadFromFiler(reader);
- if (archiveVersion = 1) then
- begin
- FQuaternion.ReadFromFiler(reader);
- FTransformMode := TgxSkeletonFrameTransform(ReadInteger);
- end;
- end
- else
- RaiseFilerException(archiveVersion);
- FlushLocalMatrixList;
- end;
- procedure TgxSkeletonFrame.SetPosition(const val: TgxAffineVectorList);
- begin
- FPosition.Assign(val);
- end;
- procedure TgxSkeletonFrame.SetRotation(const val: TgxAffineVectorList);
- begin
- FRotation.Assign(val);
- end;
- procedure TgxSkeletonFrame.SetQuaternion(const val: TgxQuaternionList);
- begin
- FQuaternion.Assign(val);
- end;
- function TgxSkeletonFrame.LocalMatrixList: PMatrixArray;
- var
- i: Integer;
- s, c: Single;
- mat, rmat: TMatrix4f;
- quat: TQuaternion;
- begin
- if not Assigned(FLocalMatrixList) then
- begin
- case FTransformMode of
- sftRotation:
- begin
- FLocalMatrixList := AllocMem(SizeOf(TMatrix4f) * Rotation.Count);
- for i := 0 to Rotation.Count - 1 do
- begin
- if Rotation[i].X <> 0 then
- begin
- SinCosine(Rotation[i].X, s, c);
- mat := CreateRotationMatrixX(s, c);
- end
- else
- mat := IdentityHmgMatrix;
- if Rotation[i].Y <> 0 then
- begin
- SinCosine(Rotation[i].Y, s, c);
- rmat := CreateRotationMatrixY(s, c);
- mat := MatrixMultiply(mat, rmat);
- end;
- if Rotation[i].Z <> 0 then
- begin
- SinCosine(Rotation[i].Z, s, c);
- rmat := CreateRotationMatrixZ(s, c);
- mat := MatrixMultiply(mat, rmat);
- end;
- mat.W.X := Position[i].X;
- mat.W.Y := Position[i].Y;
- mat.W.Z := Position[i].Z;
- FLocalMatrixList^[i] := mat;
- end;
- end;
- sftQuaternion:
- begin
- FLocalMatrixList := AllocMem(SizeOf(TMatrix4f) * Quaternion.Count);
- for i := 0 to Quaternion.Count - 1 do
- begin
- quat := Quaternion[i];
- mat := QuaternionToMatrix(quat);
- mat.W.X := Position[i].X;
- mat.W.Y := Position[i].Y;
- mat.W.Z := Position[i].Z;
- mat.W.W := 1;
- FLocalMatrixList^[i] := mat;
- end;
- end;
- end;
- end;
- Result := FLocalMatrixList;
- end;
- procedure TgxSkeletonFrame.FlushLocalMatrixList;
- begin
- if Assigned(FLocalMatrixList) then
- begin
- FreeMem(FLocalMatrixList);
- FLocalMatrixList := nil;
- end;
- end;
- procedure TgxSkeletonFrame.ConvertQuaternionsToRotations(KeepQuaternions: Boolean = True);
- var
- i: Integer;
- t: TTransformations;
- m: TMatrix4f;
- begin
- Rotation.Clear;
- for i := 0 to Quaternion.Count - 1 do
- begin
- m := QuaternionToMatrix(Quaternion[i]);
- if MatrixDecompose(m, t) then
- Rotation.Add(t[ttRotateX], t[ttRotateY], t[ttRotateZ])
- else
- Rotation.Add(NullVector);
- end;
- if not KeepQuaternions then
- Quaternion.Clear;
- end;
- procedure TgxSkeletonFrame.ConvertRotationsToQuaternions(KeepRotations: Boolean = True);
- var
- i: Integer;
- mat, rmat: TMatrix4f;
- s, c: Single;
- begin
- Quaternion.Clear;
- for i := 0 to Rotation.Count - 1 do
- begin
- mat := IdentityHmgMatrix;
- SinCosine(Rotation[i].X, s, c);
- rmat := CreateRotationMatrixX(s, c);
- mat := MatrixMultiply(mat, rmat);
- SinCosine(Rotation[i].Y, s, c);
- rmat := CreateRotationMatrixY(s, c);
- mat := MatrixMultiply(mat, rmat);
- SinCosine(Rotation[i].Z, s, c);
- rmat := CreateRotationMatrixZ(s, c);
- mat := MatrixMultiply(mat, rmat);
- Quaternion.Add(QuaternionFromMatrix(mat));
- end;
- if not KeepRotations then
- Rotation.Clear;
- end;
- // ------------------
- // ------------------ TgxSkeletonFrameList ------------------
- // ------------------
- constructor TgxSkeletonFrameList.CreateOwned(aOwner: TPersistent);
- begin
- FOwner := aOwner;
- Create;
- end;
- destructor TgxSkeletonFrameList.Destroy;
- begin
- Clear;
- inherited;
- end;
- procedure TgxSkeletonFrameList.ReadFromFiler(reader: TgxVirtualReader);
- var
- i: Integer;
- begin
- inherited;
- for i := 0 to Count - 1 do
- Items[i].FOwner := Self;
- end;
- procedure TgxSkeletonFrameList.Clear;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- with Items[i] do
- begin
- FOwner := nil;
- Free;
- end;
- inherited;
- end;
- function TgxSkeletonFrameList.GetSkeletonFrame(Index: Integer): TgxSkeletonFrame;
- begin
- Result := TgxSkeletonFrame(list^[Index]);
- end;
- procedure TgxSkeletonFrameList.ConvertQuaternionsToRotations(KeepQuaternions: Boolean = True; SetTransformMode: Boolean = True);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- begin
- Items[i].ConvertQuaternionsToRotations(KeepQuaternions);
- if SetTransformMode then
- Items[i].TransformMode := sftRotation;
- end;
- end;
- procedure TgxSkeletonFrameList.ConvertRotationsToQuaternions(KeepRotations: Boolean = True; SetTransformMode: Boolean = True);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- begin
- Items[i].ConvertRotationsToQuaternions(KeepRotations);
- if SetTransformMode then
- Items[i].TransformMode := sftQuaternion;
- end;
- end;
- // ------------------
- // ------------------ TgxSkeletonBoneList ------------------
- // ------------------
- constructor TgxSkeletonBoneList.CreateOwned(aOwner: TgxSkeleton);
- begin
- FSkeleton := aOwner;
- Create;
- end;
- constructor TgxSkeletonBoneList.Create;
- begin
- inherited;
- FGlobalMatrix := IdentityHmgMatrix;
- end;
- destructor TgxSkeletonBoneList.Destroy;
- begin
- Clean;
- inherited;
- end;
- procedure TgxSkeletonBoneList.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- // nothing, yet
- end;
- end;
- procedure TgxSkeletonBoneList.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion, i: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- // nothing, yet
- end
- else
- RaiseFilerException(archiveVersion);
- for i := 0 to Count - 1 do
- Items[i].FOwner := Self;
- end;
- procedure TgxSkeletonBoneList.AfterObjectCreatedByReader(Sender: TObject);
- begin
- with (Sender as TgxSkeletonBone) do
- begin
- FOwner := Self;
- FSkeleton := Self.Skeleton;
- end;
- end;
- function TgxSkeletonBoneList.GetSkeletonBone(Index: Integer): TgxSkeletonBone;
- begin
- Result := TgxSkeletonBone(list^[Index]);
- end;
- function TgxSkeletonBoneList.BoneByID(anID: Integer): TgxSkeletonBone;
- var
- i: Integer;
- begin
- Result := nil;
- for i := 0 to Count - 1 do
- begin
- Result := Items[i].BoneByID(anID);
- if Assigned(Result) then
- Break;
- end;
- end;
- function TgxSkeletonBoneList.BoneByName(const aName: string): TgxSkeletonBone;
- var
- i: Integer;
- begin
- Result := nil;
- for i := 0 to Count - 1 do
- begin
- Result := Items[i].BoneByName(aName);
- if Assigned(Result) then
- Break;
- end;
- end;
- function TgxSkeletonBoneList.BoneCount: Integer;
- var
- i: Integer;
- begin
- Result := 1;
- for i := 0 to Count - 1 do
- Inc(Result, Items[i].BoneCount);
- end;
- procedure TgxSkeletonBoneList.PrepareGlobalMatrices;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- Items[i].PrepareGlobalMatrices;
- end;
- // ------------------
- // ------------------ TgxSkeletonRootBoneList ------------------
- // ------------------
- procedure TgxSkeletonRootBoneList.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- // nothing, yet
- end;
- end;
- procedure TgxSkeletonRootBoneList.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion, i: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- // nothing, yet
- end
- else
- RaiseFilerException(archiveVersion);
- for i := 0 to Count - 1 do
- Items[i].FOwner := Self;
- end;
- procedure TgxSkeletonRootBoneList.BuildList(var mrci: TgxRenderContextInfo);
- var
- i: Integer;
- begin
- // root node setups and restore OpenGL stuff
- mrci.gxStates.Disable(stColorMaterial);
- mrci.gxStates.Disable(stLighting);
- glColor3f(1, 1, 1);
- // render root-bones
- for i := 0 to Count - 1 do
- Items[i].BuildList(mrci);
- end;
- // ------------------
- // ------------------ TgxSkeletonBone ------------------
- // ------------------
- constructor TgxSkeletonBone.CreateOwned(aOwner: TgxSkeletonBoneList);
- begin
- FOwner := aOwner;
- aOwner.Add(Self);
- FSkeleton := aOwner.Skeleton;
- Create;
- end;
- constructor TgxSkeletonBone.Create;
- begin
- FColor := $FFFFFFFF; // opaque white
- inherited;
- end;
- destructor TgxSkeletonBone.Destroy;
- begin
- if Assigned(Owner) then
- Owner.Remove(Self);
- inherited Destroy;
- end;
- procedure TgxSkeletonBone.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- WriteString(FName);
- WriteInteger(FBoneID);
- WriteInteger(Integer(FColor));
- end;
- end;
- procedure TgxSkeletonBone.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion, i: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- FName := ReadString;
- FBoneID := ReadInteger;
- FColor := Cardinal(ReadInteger);
- end
- else
- RaiseFilerException(archiveVersion);
- for i := 0 to Count - 1 do
- Items[i].FOwner := Self;
- end;
- procedure TgxSkeletonBone.BuildList(var mrci: TgxRenderContextInfo);
- procedure IssueColor(Color: Cardinal);
- begin
- glColor4f(GetRValue(Color) / 255, GetGValue(Color) / 255, GetBValue(Color) / 255, ((Color shr 24) and 255) / 255);
- end;
- var
- i: Integer;
- begin
- // point for self
- mrci.gxStates.PointSize := 5;
- glBegin(GL_POINTS);
- IssueColor(Color);
- glVertex3fv(@GlobalMatrix.W.X);
- glEnd;
- // parent-self bone line
- if Owner is TgxSkeletonBone then
- begin
- glBegin(GL_LINES);
- glVertex3fv(@TgxSkeletonBone(Owner).GlobalMatrix.W.X);
- glVertex3fv(@GlobalMatrix.W.X);
- glEnd;
- end;
- // render sub-bones
- for i := 0 to Count - 1 do
- Items[i].BuildList(mrci);
- end;
- function TgxSkeletonBone.GetSkeletonBone(Index: Integer): TgxSkeletonBone;
- begin
- Result := TgxSkeletonBone(list^[Index]);
- end;
- procedure TgxSkeletonBone.SetColor(const val: Cardinal);
- begin
- FColor := val;
- end;
- function TgxSkeletonBone.BoneByID(anID: Integer): TgxSkeletonBone;
- begin
- if BoneID = anID then
- Result := Self
- else
- Result := inherited BoneByID(anID);
- end;
- function TgxSkeletonBone.BoneByName(const aName: string): TgxSkeletonBone;
- begin
- if Name = aName then
- Result := Self
- else
- Result := inherited BoneByName(aName);
- end;
- procedure TgxSkeletonBone.Clean;
- begin
- BoneID := 0;
- Name := '';
- inherited;
- end;
- procedure TgxSkeletonBone.PrepareGlobalMatrices;
- begin
- if (Skeleton.FRagDollEnabled) then
- Exit; // ragdoll
- FGlobalMatrix := MatrixMultiply(Skeleton.CurrentFrame.LocalMatrixList^[BoneID], TgxSkeletonBoneList(Owner).FGlobalMatrix);
- inherited;
- end;
- procedure TgxSkeletonBone.SetGlobalMatrix(Matrix: TMatrix4f); // ragdoll
- begin
- FGlobalMatrix := Matrix;
- end;
- procedure TgxSkeletonBone.SetGlobalMatrixForRagDoll(RagDollMatrix: TMatrix4f);
- // ragdoll
- begin
- FGlobalMatrix := MatrixMultiply(RagDollMatrix, Skeleton.Owner.InvAbsoluteMatrix);
- inherited;
- end;
- // ------------------
- // ------------------ TgxSkeletonCollider ------------------
- // ------------------
- constructor TgxSkeletonCollider.Create;
- begin
- inherited;
- FLocalMatrix := IdentityHmgMatrix;
- FGlobalMatrix := IdentityHmgMatrix;
- FAutoUpdate := True;
- end;
- constructor TgxSkeletonCollider.CreateOwned(aOwner: TgxSkeletonColliderList);
- begin
- Create;
- FOwner := aOwner;
- if Assigned(FOwner) then
- FOwner.Add(Self);
- end;
- procedure TgxSkeletonCollider.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- if Assigned(FBone) then
- WriteInteger(FBone.BoneID)
- else
- WriteInteger(-1);
- Write(FLocalMatrix, SizeOf(TMatrix4f));
- end;
- end;
- procedure TgxSkeletonCollider.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- FBoneID := ReadInteger;
- Read(FLocalMatrix, SizeOf(TMatrix4f));
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TgxSkeletonCollider.AlignCollider;
- var
- mat: TMatrix4f;
- begin
- if Assigned(FBone) then
- begin
- if Owner.Owner is TgxSkeleton then
- if TgxSkeleton(Owner.Owner).Owner is TgxBaseSceneObject then
- mat := MatrixMultiply(FBone.GlobalMatrix, TgxBaseSceneObject(TgxSkeleton(Owner.Owner).Owner).AbsoluteMatrix)
- else
- mat := FBone.GlobalMatrix;
- MatrixMultiply(FLocalMatrix, mat, FGlobalMatrix);
- end
- else
- FGlobalMatrix := FLocalMatrix;
- end;
- procedure TgxSkeletonCollider.SetBone(const val: TgxSkeletonBone);
- begin
- if val <> FBone then
- FBone := val;
- end;
- procedure TgxSkeletonCollider.SetLocalMatrix(const val: TMatrix4f);
- begin
- FLocalMatrix := val;
- end;
- // ------------------
- // ------------------ TgxSkeletonColliderList ------------------
- // ------------------
- constructor TgxSkeletonColliderList.CreateOwned(aOwner: TPersistent);
- begin
- Create;
- FOwner := aOwner;
- end;
- destructor TgxSkeletonColliderList.Destroy;
- begin
- Clear;
- inherited;
- end;
- function TgxSkeletonColliderList.GetSkeletonCollider(Index: Integer): TgxSkeletonCollider;
- begin
- Result := TgxSkeletonCollider(inherited Get(index));
- end;
- procedure TgxSkeletonColliderList.ReadFromFiler(reader: TgxVirtualReader);
- var
- i: Integer;
- begin
- inherited;
- for i := 0 to Count - 1 do
- begin
- Items[i].FOwner := Self;
- if (Owner is TgxSkeleton) and (Items[i].FBoneID <> -1) then
- Items[i].Bone := TgxSkeleton(Owner).BoneByID(Items[i].FBoneID);
- end;
- end;
- procedure TgxSkeletonColliderList.Clear;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- begin
- Items[i].FOwner := nil;
- Items[i].Free;
- end;
- inherited;
- end;
- procedure TgxSkeletonColliderList.AlignColliders;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- if Items[i].AutoUpdate then
- Items[i].AlignCollider;
- end;
- // ------------------
- // ------------------ TgxSkeleton ------------------
- // ------------------
- constructor TgxSkeleton.CreateOwned(aOwner: TgxBaseMesh);
- begin
- FOwner := aOwner;
- Create;
- end;
- constructor TgxSkeleton.Create;
- begin
- inherited Create;
- FRootBones := TgxSkeletonRootBoneList.CreateOwned(Self);
- FFrames := TgxSkeletonFrameList.CreateOwned(Self);
- FColliders := TgxSkeletonColliderList.CreateOwned(Self);
- end;
- destructor TgxSkeleton.Destroy;
- begin
- FlushBoneByIDCache;
- FCurrentFrame.Free;
- FFrames.Free;
- FRootBones.Free;
- FColliders.Free;
- inherited Destroy;
- end;
- procedure TgxSkeleton.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- if FColliders.Count > 0 then
- WriteInteger(1) // Archive Version 1 : with colliders
- else
- WriteInteger(0); // Archive Version 0
- FRootBones.WriteToFiler(writer);
- FFrames.WriteToFiler(writer);
- if FColliders.Count > 0 then
- FColliders.WriteToFiler(writer);
- end;
- end;
- procedure TgxSkeleton.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if (archiveVersion = 0) or (archiveVersion = 1) then
- with reader do
- begin
- FRootBones.ReadFromFiler(reader);
- FFrames.ReadFromFiler(reader);
- if (archiveVersion = 1) then
- FColliders.ReadFromFiler(reader);
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TgxSkeleton.SetRootBones(const val: TgxSkeletonRootBoneList);
- begin
- FRootBones.Assign(val);
- end;
- procedure TgxSkeleton.SetFrames(const val: TgxSkeletonFrameList);
- begin
- FFrames.Assign(val);
- end;
- function TgxSkeleton.GetCurrentFrame: TgxSkeletonFrame;
- begin
- if not Assigned(FCurrentFrame) then
- FCurrentFrame := TgxSkeletonFrame(FFrames.Items[0].CreateClone);
- Result := FCurrentFrame;
- end;
- procedure TgxSkeleton.SetCurrentFrame(val: TgxSkeletonFrame);
- begin
- if Assigned(FCurrentFrame) then
- FCurrentFrame.Free;
- FCurrentFrame := TgxSkeletonFrame(val.CreateClone);
- end;
- procedure TgxSkeleton.SetColliders(const val: TgxSkeletonColliderList);
- begin
- FColliders.Assign(val);
- end;
- procedure TgxSkeleton.FlushBoneByIDCache;
- begin
- FBonesByIDCache.Free;
- FBonesByIDCache := nil;
- end;
- function TgxSkeleton.BoneByID(anID: Integer): TgxSkeletonBone;
- procedure CollectBones(Bone: TgxSkeletonBone);
- var
- i: Integer;
- begin
- if Bone.BoneID >= FBonesByIDCache.Count then
- FBonesByIDCache.Count := Bone.BoneID + 1;
- FBonesByIDCache[Bone.BoneID] := Bone;
- for i := 0 to Bone.Count - 1 do
- CollectBones(Bone[i]);
- end;
- var
- i: Integer;
- begin
- if not Assigned(FBonesByIDCache) then
- begin
- FBonesByIDCache := TList.Create;
- for i := 0 to RootBones.Count - 1 do
- CollectBones(RootBones[i]);
- end;
- Result := TgxSkeletonBone(FBonesByIDCache[anID])
- end;
- function TgxSkeleton.BoneByName(const aName: string): TgxSkeletonBone;
- begin
- Result := RootBones.BoneByName(aName);
- end;
- function TgxSkeleton.BoneCount: Integer;
- begin
- Result := RootBones.BoneCount;
- end;
- procedure TgxSkeleton.MorphTo(frameIndex: Integer);
- begin
- CurrentFrame := Frames[frameIndex];
- end;
- procedure TgxSkeleton.MorphTo(frame: TgxSkeletonFrame);
- begin
- CurrentFrame := frame;
- end;
- procedure TgxSkeleton.Lerp(frameIndex1, frameIndex2: Integer; lerpFactor: Single);
- begin
- if Assigned(FCurrentFrame) then
- FCurrentFrame.Free;
- FCurrentFrame := TgxSkeletonFrame.Create;
- FCurrentFrame.TransformMode := Frames[frameIndex1].TransformMode;
- with FCurrentFrame do
- begin
- Position.Lerp(Frames[frameIndex1].Position, Frames[frameIndex2].Position, lerpFactor);
- case TransformMode of
- sftRotation:
- Rotation.AngleLerp(Frames[frameIndex1].Rotation, Frames[frameIndex2].Rotation, lerpFactor);
- sftQuaternion:
- Quaternion.Lerp(Frames[frameIndex1].Quaternion, Frames[frameIndex2].Quaternion, lerpFactor);
- end;
- end;
- end;
- procedure TgxSkeleton.BlendedLerps(const lerpInfos: array of TGXBlendedLerpInfo);
- var
- i, n: Integer;
- blendPositions: TgxAffineVectorList;
- blendRotations: TgxAffineVectorList;
- blendQuaternions: TgxQuaternionList;
- begin
- n := High(lerpInfos) - Low(lerpInfos) + 1;
- Assert(n >= 1);
- i := Low(lerpInfos);
- if n = 1 then
- begin
- // use fast lerp (no blend)
- with lerpInfos[i] do
- Lerp(frameIndex1, frameIndex2, lerpFactor);
- end
- else
- begin
- if Assigned(FCurrentFrame) then
- FCurrentFrame.Free;
- FCurrentFrame := TgxSkeletonFrame.Create;
- FCurrentFrame.TransformMode := Frames[lerpInfos[i].frameIndex1].TransformMode;
- with FCurrentFrame do
- begin
- blendPositions := TgxAffineVectorList.Create;
- // lerp first item separately
- Position.Lerp(Frames[lerpInfos[i].frameIndex1].Position, Frames[lerpInfos[i].frameIndex2].Position,
- lerpInfos[i].lerpFactor);
- if lerpInfos[i].weight <> 1 then
- Position.Scale(lerpInfos[i].weight);
- Inc(i);
- // combine the other items
- while i <= High(lerpInfos) do
- begin
- if not Assigned(lerpInfos[i].externalPositions) then
- begin
- blendPositions.Lerp(Frames[lerpInfos[i].frameIndex1].Position, Frames[lerpInfos[i].frameIndex2].Position,
- lerpInfos[i].lerpFactor);
- Position.AngleCombine(blendPositions, 1);
- end
- else
- Position.Combine(lerpInfos[i].externalPositions, 1);
- Inc(i);
- end;
- blendPositions.Free;
- i := Low(lerpInfos);
- case TransformMode of
- sftRotation:
- begin
- blendRotations := TgxAffineVectorList.Create;
- // lerp first item separately
- Rotation.AngleLerp(Frames[lerpInfos[i].frameIndex1].Rotation, Frames[lerpInfos[i].frameIndex2].Rotation,
- lerpInfos[i].lerpFactor);
- Inc(i);
- // combine the other items
- while i <= High(lerpInfos) do
- begin
- if not Assigned(lerpInfos[i].externalRotations) then
- begin
- blendRotations.AngleLerp(Frames[lerpInfos[i].frameIndex1].Rotation, Frames[lerpInfos[i].frameIndex2].Rotation,
- lerpInfos[i].lerpFactor);
- Rotation.AngleCombine(blendRotations, 1);
- end
- else
- Rotation.AngleCombine(lerpInfos[i].externalRotations, 1);
- Inc(i);
- end;
- blendRotations.Free;
- end;
- sftQuaternion:
- begin
- blendQuaternions := TgxQuaternionList.Create;
- // Initial frame lerp
- Quaternion.Lerp(Frames[lerpInfos[i].frameIndex1].Quaternion, Frames[lerpInfos[i].frameIndex2].Quaternion,
- lerpInfos[i].lerpFactor);
- Inc(i);
- // Combine the lerped frames together
- while i <= High(lerpInfos) do
- begin
- if not Assigned(lerpInfos[i].externalQuaternions) then
- begin
- blendQuaternions.Lerp(Frames[lerpInfos[i].frameIndex1].Quaternion, Frames[lerpInfos[i].frameIndex2].Quaternion,
- lerpInfos[i].lerpFactor);
- Quaternion.Combine(blendQuaternions, 1);
- end
- else
- Quaternion.Combine(lerpInfos[i].externalQuaternions, 1);
- Inc(i);
- end;
- blendQuaternions.Free;
- end;
- end;
- end;
- end;
- end;
- procedure TgxSkeleton.MakeSkeletalTranslationStatic(startFrame, endFrame: Integer);
- var
- delta: TAffineVector;
- i: Integer;
- f: Single;
- begin
- if endFrame <= startFrame then
- Exit;
- delta := VectorSubtract(Frames[endFrame].Position[0], Frames[startFrame].Position[0]);
- f := -1 / (endFrame - startFrame);
- for i := startFrame to endFrame do
- Frames[i].Position[0] := VectorCombine(Frames[i].Position[0], delta, 1, (i - startFrame) * f);
- end;
- procedure TgxSkeleton.MakeSkeletalRotationDelta(startFrame, endFrame: Integer);
- var
- i, j: Integer;
- v: TAffineVector;
- begin
- if endFrame <= startFrame then
- Exit;
- for i := startFrame to endFrame do
- begin
- for j := 0 to Frames[i].Position.Count - 1 do
- begin
- Frames[i].Position[j] := NullVector;
- v := VectorSubtract(Frames[i].Rotation[j], Frames[0].Rotation[j]);
- if VectorNorm(v) < 1E-6 then
- Frames[i].Rotation[j] := NullVector
- else
- Frames[i].Rotation[j] := v;
- end;
- end;
- end;
- procedure TgxSkeleton.MorphMesh(normalize: Boolean);
- var
- i: Integer;
- Mesh: TgxBaseMeshObject;
- begin
- if Owner.MeshObjects.Count > 0 then
- begin
- RootBones.PrepareGlobalMatrices;
- if Colliders.Count > 0 then
- Colliders.AlignColliders;
- if FMorphInvisibleParts then
- for i := 0 to Owner.MeshObjects.Count - 1 do
- begin
- Mesh := Owner.MeshObjects.Items[i];
- if (Mesh is TgxSkeletonMeshObject) then
- TgxSkeletonMeshObject(Mesh).ApplyCurrentSkeletonFrame(normalize);
- end
- else
- for i := 0 to Owner.MeshObjects.Count - 1 do
- begin
- Mesh := Owner.MeshObjects.Items[i];
- if (Mesh is TgxSkeletonMeshObject) and Mesh.Visible then
- TgxSkeletonMeshObject(Mesh).ApplyCurrentSkeletonFrame(normalize);
- end
- end;
- end;
- procedure TgxSkeleton.Synchronize(reference: TgxSkeleton);
- begin
- CurrentFrame.Assign(reference.CurrentFrame);
- MorphMesh(True);
- end;
- procedure TgxSkeleton.Clear;
- begin
- FlushBoneByIDCache;
- RootBones.Clean;
- Frames.Clear;
- FCurrentFrame.Free;
- FCurrentFrame := nil;
- FColliders.Clear;
- end;
- procedure TgxSkeleton.StartRagdoll; // ragdoll
- var
- i: Integer;
- Mesh: TgxBaseMeshObject;
- begin
- if FRagDollEnabled then
- Exit
- else
- FRagDollEnabled := True;
- if Owner.MeshObjects.Count > 0 then
- begin
- for i := 0 to Owner.MeshObjects.Count - 1 do
- begin
- Mesh := Owner.MeshObjects.Items[i];
- if Mesh is TgxSkeletonMeshObject then
- begin
- TgxSkeletonMeshObject(Mesh).BackupBoneMatrixInvertedMeshes;
- TgxSkeletonMeshObject(Mesh).PrepareBoneMatrixInvertedMeshes;
- end;
- end;
- end;
- end;
- procedure TgxSkeleton.StopRagdoll; // ragdoll
- var
- i: Integer;
- Mesh: TgxBaseMeshObject;
- begin
- FRagDollEnabled := False;
- if Owner.MeshObjects.Count > 0 then
- begin
- for i := 0 to Owner.MeshObjects.Count - 1 do
- begin
- Mesh := Owner.MeshObjects.Items[i];
- if Mesh is TgxSkeletonMeshObject then
- TgxSkeletonMeshObject(Mesh).RestoreBoneMatrixInvertedMeshes;
- end;
- end;
- end;
- // ------------------
- // ------------------ TgxMeshObject ------------------
- // ------------------
- constructor TgxMeshObject.CreateOwned(aOwner: TgxMeshObjectList);
- begin
- FOwner := aOwner;
- Create;
- if Assigned(FOwner) then
- FOwner.Add(Self);
- end;
- constructor TgxMeshObject.Create;
- begin
- FMode := momTriangles;
- FTexCoords := TgxAffineVectorList.Create;
- FLightMapTexCoords := TgxAffineVectorList.Create;
- FColors := TgxVectorList.Create;
- FFaceGroups := TgxFaceGroups.CreateOwned(Self);
- FTexCoordsEx := TList.Create;
- FTangentsTexCoordIndex := 1;
- FBinormalsTexCoordIndex := 2;
- FUseVBO := vVectorFileObjectsEnableVBOByDefault;
- inherited;
- end;
- destructor TgxMeshObject.Destroy;
- var
- i: Integer;
- begin
- FVerticesVBO.Free;
- FNormalsVBO.Free;
- FColorsVBO.Free;
- for i := 0 to high(FTexCoordsVBO) do
- FTexCoordsVBO[i].Free;
- FLightmapTexCoordsVBO.Free;
- FFaceGroups.Free;
- FColors.Free;
- FTexCoords.Free;
- FLightMapTexCoords.Free;
- for i := 0 to FTexCoordsEx.Count - 1 do
- TgxVectorList(FTexCoordsEx[i]).Free;
- FTexCoordsEx.Free;
- if Assigned(FOwner) then
- FOwner.Remove(Self);
- inherited;
- end;
- procedure TgxMeshObject.Assign(Source: TPersistent);
- var
- i: Integer;
- begin
- inherited Assign(Source);
- if Source is TgxMeshObject then
- begin
- FTexCoords.Assign(TgxMeshObject(Source).FTexCoords);
- FLightMapTexCoords.Assign(TgxMeshObject(Source).FLightMapTexCoords);
- FColors.Assign(TgxMeshObject(Source).FColors);
- FFaceGroups.Assign(TgxMeshObject(Source).FFaceGroups);
- FMode := TgxMeshObject(Source).FMode;
- FRenderingOptions := TgxMeshObject(Source).FRenderingOptions;
- FBinormalsTexCoordIndex := TgxMeshObject(Source).FBinormalsTexCoordIndex;
- FTangentsTexCoordIndex := TgxMeshObject(Source).FTangentsTexCoordIndex;
- // Clear FTexCoordsEx.
- for i := 0 to FTexCoordsEx.Count - 1 do
- TgxVectorList(FTexCoordsEx[i]).Free;
- FTexCoordsEx.Count := TgxMeshObject(Source).FTexCoordsEx.Count;
- // Fill FTexCoordsEx.
- for i := 0 to FTexCoordsEx.Count - 1 do
- begin
- FTexCoordsEx[i] := TgxVectorList.Create;
- TgxVectorList(FTexCoordsEx[i]).Assign(TgxMeshObject(Source).FTexCoordsEx[i]);
- end;
- end;
- end;
- procedure TgxMeshObject.WriteToFiler(writer: TgxVirtualWriter);
- var
- i: Integer;
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(3); // Archive Version 3
- FTexCoords.WriteToFiler(writer);
- FLightMapTexCoords.WriteToFiler(writer);
- FColors.WriteToFiler(writer);
- FFaceGroups.WriteToFiler(writer);
- WriteInteger(Integer(FMode));
- WriteInteger(SizeOf(FRenderingOptions));
- Write(FRenderingOptions, SizeOf(FRenderingOptions));
- WriteInteger(FTexCoordsEx.Count);
- for i := 0 to FTexCoordsEx.Count - 1 do
- TexCoordsEx[i].WriteToFiler(writer);
- WriteInteger(BinormalsTexCoordIndex);
- WriteInteger(TangentsTexCoordIndex);
- end;
- end;
- procedure TgxMeshObject.ReadFromFiler(reader: TgxVirtualReader);
- var
- i, Count, archiveVersion: Integer;
- lOldLightMapTexCoords: TgxTexPointList;
- tc: TTexPoint;
- size, ro: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion in [0 .. 3] then
- with reader do
- begin
- FTexCoords.ReadFromFiler(reader);
- if archiveVersion = 0 then
- begin
- // FLightMapTexCoords did not exist back than.
- FLightMapTexCoords.Clear;
- end
- else if (archiveVersion = 1) or (archiveVersion = 2) then
- begin
- lOldLightMapTexCoords := TgxTexPointList.CreateFromFiler(reader);
- for i := 0 to lOldLightMapTexCoords.Count - 1 do
- begin
- tc := lOldLightMapTexCoords[i];
- FLightMapTexCoords.Add(tc.s, tc.t);
- end;
- lOldLightMapTexCoords.Free;
- end
- else
- begin
- // Load FLightMapTexCoords the normal way.
- FLightMapTexCoords.ReadFromFiler(reader);
- end;
- FColors.ReadFromFiler(reader);
- FFaceGroups.ReadFromFiler(reader);
- FMode := TgxMeshObjectMode(ReadInteger);
- size := ReadInteger;
- ro := 0;
- Read(ro, size);
- FRenderingOptions := TgxMeshObjectRenderingOptions(Byte(ro));
- if archiveVersion >= 2 then
- begin
- Count := ReadInteger;
- for i := 0 to Count - 1 do
- TexCoordsEx[i].ReadFromFiler(reader);
- BinormalsTexCoordIndex := ReadInteger;
- TangentsTexCoordIndex := ReadInteger;
- end;
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TgxMeshObject.Clear;
- var
- i: Integer;
- begin
- inherited;
- FFaceGroups.Clear;
- FColors.Clear;
- FTexCoords.Clear;
- FLightMapTexCoords.Clear;
- for i := 0 to FTexCoordsEx.Count - 1 do
- TexCoordsEx[i].Clear;
- end;
- function TgxMeshObject.ExtractTriangles(texCoords: TgxAffineVectorList = nil; normals: TgxAffineVectorList = nil)
- : TgxAffineVectorList;
- begin
- case mode of
- momTriangles:
- begin
- Result := inherited ExtractTriangles;
- if Assigned(texCoords) then
- texCoords.Assign(Self.texCoords);
- if Assigned(normals) then
- normals.Assign(Self.normals);
- end;
- momTriangleStrip:
- begin
- Result := TgxAffineVectorList.Create;
- ConvertStripToList(Vertices, Result);
- if Assigned(texCoords) then
- ConvertStripToList(Self.texCoords, texCoords);
- if Assigned(normals) then
- ConvertStripToList(Self.normals, normals);
- end;
- momFaceGroups:
- begin
- Result := TgxAffineVectorList.Create;
- FaceGroups.AddToTriangles(Result, texCoords, normals);
- end;
- else
- Result := nil;
- Assert(False);
- end;
- end;
- function TgxMeshObject.TriangleCount: Integer;
- var
- i: Integer;
- begin
- case mode of
- momTriangles:
- Result := (Vertices.Count div 3);
- momTriangleStrip:
- begin
- Result := Vertices.Count - 2;
- if Result < 0 then
- Result := 0;
- end;
- momFaceGroups:
- begin
- Result := 0;
- for i := 0 to FaceGroups.Count - 1 do
- Result := Result + FaceGroups[i].TriangleCount;
- end;
- else
- Result := 0;
- Assert(False);
- end;
- end;
- procedure TgxMeshObject.PrepareMaterialLibraryCache(matLib: TgxMaterialLibrary);
- begin
- FaceGroups.PrepareMaterialLibraryCache(matLib);
- end;
- procedure TgxMeshObject.DropMaterialLibraryCache;
- begin
- FaceGroups.DropMaterialLibraryCache;
- end;
- procedure TgxMeshObject.GetExtents(out min, max: TAffineVector);
- begin
- if FVertices.Revision <> FExtentCacheRevision then
- begin
- FVertices.GetExtents(FExtentCache.min, FExtentCache.max);
- FExtentCacheRevision := FVertices.Revision;
- end;
- min := FExtentCache.min;
- max := FExtentCache.max;
- end;
- procedure TgxMeshObject.GetExtents(out aabb: TAABB);
- begin
- if FVertices.Revision <> FExtentCacheRevision then
- begin
- FVertices.GetExtents(FExtentCache.min, FExtentCache.max);
- FExtentCacheRevision := FVertices.Revision;
- end;
- aabb := FExtentCache;
- end;
- function TgxMeshObject.GetBarycenter: TVector4f;
- var
- dMin, dMax: TAffineVector;
- begin
- GetExtents(dMin, dMax);
- Result.X := (dMin.X + dMax.X) / 2;
- Result.Y := (dMin.Y + dMax.Y) / 2;
- Result.Z := (dMin.Z + dMax.Z) / 2;
- Result.W := 0;
- end;
- procedure TgxMeshObject.Prepare;
- var
- i: Integer;
- begin
- ValidBuffers := [];
- for i := 0 to FaceGroups.Count - 1 do
- FaceGroups[i].Prepare;
- end;
- function TgxMeshObject.PointInObject(const aPoint: TAffineVector): Boolean;
- var
- min, max: TAffineVector;
- begin
- GetExtents(min, max);
- Result := (aPoint.X >= min.X) and (aPoint.Y >= min.Y) and (aPoint.Z >= min.Z) and (aPoint.X <= max.X) and (aPoint.Y <= max.Y)
- and (aPoint.Z <= max.Z);
- end;
- procedure TgxMeshObject.SetTexCoords(const val: TgxAffineVectorList);
- begin
- FTexCoords.Assign(val);
- end;
- procedure TgxMeshObject.SetLightmapTexCoords(const val: TgxAffineVectorList);
- begin
- FLightMapTexCoords.Assign(val);
- end;
- procedure TgxMeshObject.SetColors(const val: TgxVectorList);
- begin
- FColors.Assign(val);
- end;
- procedure TgxMeshObject.SetTexCoordsEx(Index: Integer; const val: TgxVectorList);
- begin
- TexCoordsEx[index].Assign(val);
- end;
- function TgxMeshObject.GetTexCoordsEx(Index: Integer): TgxVectorList;
- var
- i: Integer;
- begin
- if index > FTexCoordsEx.Count - 1 then
- for i := FTexCoordsEx.Count - 1 to index do
- FTexCoordsEx.Add(TgxVectorList.Create);
- Result := TgxVectorList(FTexCoordsEx[index]);
- end;
- procedure TgxMeshObject.SetBinormals(const val: TgxVectorList);
- begin
- Binormals.Assign(val);
- end;
- function TgxMeshObject.GetBinormals: TgxVectorList;
- begin
- Result := TexCoordsEx[BinormalsTexCoordIndex];
- end;
- procedure TgxMeshObject.SetBinormalsTexCoordIndex(const val: Integer);
- begin
- Assert(val >= 0);
- if val <> FBinormalsTexCoordIndex then
- begin
- FBinormalsTexCoordIndex := val;
- end;
- end;
- procedure TgxMeshObject.SetTangents(const val: TgxVectorList);
- begin
- Tangents.Assign(val);
- end;
- function TgxMeshObject.GetTangents: TgxVectorList;
- begin
- Result := TexCoordsEx[TangentsTexCoordIndex];
- end;
- procedure TgxMeshObject.SetTangentsTexCoordIndex(const val: Integer);
- begin
- Assert(val >= 0);
- if val <> FTangentsTexCoordIndex then
- begin
- FTangentsTexCoordIndex := val;
- end;
- end;
- procedure TgxMeshObject.GetTriangleData(tri: Integer; list: TgxAffineVectorList; var v0, v1, v2: TAffineVector);
- var
- i, LastCount, Count: Integer;
- fg: TgxFGVertexIndexList;
- begin
- case mode of
- momTriangles:
- begin
- v0 := list[3 * tri];
- v1 := list[3 * tri + 1];
- v2 := list[3 * tri + 2];
- end;
- momTriangleStrip:
- begin
- v0 := list[tri];
- v1 := list[tri + 1];
- v2 := list[tri + 2];
- end;
- momFaceGroups:
- begin
- Count := 0;
- for i := 0 to FaceGroups.Count - 1 do
- begin
- LastCount := Count;
- fg := TgxFGVertexIndexList(FaceGroups[i]);
- Count := Count + fg.TriangleCount;
- if Count > tri then
- begin
- Count := tri - LastCount;
- case fg.mode of
- fgmmTriangles, fgmmFlatTriangles:
- begin
- v0 := list[fg.vertexIndices[3 * Count]];
- v1 := list[fg.vertexIndices[3 * Count + 1]];
- v2 := list[fg.vertexIndices[3 * Count + 2]];
- end;
- fgmmTriangleStrip:
- begin
- v0 := list[fg.vertexIndices[Count]];
- v1 := list[fg.vertexIndices[Count + 1]];
- v2 := list[fg.vertexIndices[Count + 2]];
- end;
- fgmmTriangleFan:
- begin
- v0 := list[fg.vertexIndices[0]];
- v1 := list[fg.vertexIndices[Count + 1]];
- v2 := list[fg.vertexIndices[Count + 2]];
- end;
- fgmmQuads:
- begin
- if Count mod 2 = 0 then
- begin
- v0 := list[fg.vertexIndices[4 * (Count div 2)]];
- v1 := list[fg.vertexIndices[4 * (Count div 2) + 1]];
- v2 := list[fg.vertexIndices[4 * (Count div 2) + 2]];
- end
- else
- begin
- v0 := list[fg.vertexIndices[4 * (Count div 2)]];
- v1 := list[fg.vertexIndices[4 * (Count div 2) + 2]];
- v2 := list[fg.vertexIndices[4 * (Count div 2) + 3]];
- end;
- end;
- else
- Assert(False);
- end;
- Break;
- end;
- end;
- end;
- else
- Assert(False);
- end;
- end;
- procedure TgxMeshObject.GetTriangleData(tri: Integer; list: TgxVectorList; var v0, v1, v2: TVector4f);
- var
- i, LastCount, Count: Integer;
- fg: TgxFGVertexIndexList;
- begin
- case mode of
- momTriangles:
- begin
- v0 := list[3 * tri];
- v1 := list[3 * tri + 1];
- v2 := list[3 * tri + 2];
- end;
- momTriangleStrip:
- begin
- v0 := list[tri];
- v1 := list[tri + 1];
- v2 := list[tri + 2];
- end;
- momFaceGroups:
- begin
- Count := 0;
- for i := 0 to FaceGroups.Count - 1 do
- begin
- LastCount := Count;
- fg := TgxFGVertexIndexList(FaceGroups[i]);
- Count := Count + fg.TriangleCount;
- if Count > tri then
- begin
- Count := tri - LastCount;
- case fg.mode of
- fgmmTriangles, fgmmFlatTriangles:
- begin
- v0 := list[fg.vertexIndices[3 * Count]];
- v1 := list[fg.vertexIndices[3 * Count + 1]];
- v2 := list[fg.vertexIndices[3 * Count + 2]];
- end;
- fgmmTriangleStrip:
- begin
- v0 := list[fg.vertexIndices[Count]];
- v1 := list[fg.vertexIndices[Count + 1]];
- v2 := list[fg.vertexIndices[Count + 2]];
- end;
- fgmmTriangleFan:
- begin
- v0 := list[fg.vertexIndices[0]];
- v1 := list[fg.vertexIndices[Count + 1]];
- v2 := list[fg.vertexIndices[Count + 2]];
- end;
- fgmmQuads:
- begin
- if Count mod 2 = 0 then
- begin
- v0 := list[fg.vertexIndices[4 * (Count div 2)]];
- v1 := list[fg.vertexIndices[4 * (Count div 2) + 1]];
- v2 := list[fg.vertexIndices[4 * (Count div 2) + 2]];
- end
- else
- begin
- v0 := list[fg.vertexIndices[4 * (Count div 2)]];
- v1 := list[fg.vertexIndices[4 * (Count div 2) + 2]];
- v2 := list[fg.vertexIndices[4 * (Count div 2) + 3]];
- end;
- end;
- else
- Assert(False);
- end;
- Break;
- end;
- end;
- end;
- else
- Assert(False);
- end;
- end;
- procedure TgxMeshObject.SetTriangleData(tri: Integer; list: TgxAffineVectorList; const v0, v1, v2: TAffineVector);
- var
- i, LastCount, Count: Integer;
- fg: TgxFGVertexIndexList;
- begin
- case mode of
- momTriangles:
- begin
- list[3 * tri] := v0;
- list[3 * tri + 1] := v1;
- list[3 * tri + 2] := v2;
- end;
- momTriangleStrip:
- begin
- list[tri] := v0;
- list[tri + 1] := v1;
- list[tri + 2] := v2;
- end;
- momFaceGroups:
- begin
- Count := 0;
- for i := 0 to FaceGroups.Count - 1 do
- begin
- LastCount := Count;
- fg := TgxFGVertexIndexList(FaceGroups[i]);
- Count := Count + fg.TriangleCount;
- if Count > tri then
- begin
- Count := tri - LastCount;
- case fg.mode of
- fgmmTriangles, fgmmFlatTriangles:
- begin
- list[fg.vertexIndices[3 * Count]] := v0;
- list[fg.vertexIndices[3 * Count + 1]] := v1;
- list[fg.vertexIndices[3 * Count + 2]] := v2;
- end;
- fgmmTriangleStrip:
- begin
- list[fg.vertexIndices[Count]] := v0;
- list[fg.vertexIndices[Count + 1]] := v1;
- list[fg.vertexIndices[Count + 2]] := v2;
- end;
- fgmmTriangleFan:
- begin
- list[fg.vertexIndices[0]] := v0;
- list[fg.vertexIndices[Count + 1]] := v1;
- list[fg.vertexIndices[Count + 2]] := v2;
- end;
- fgmmQuads:
- begin
- if Count mod 2 = 0 then
- begin
- list[fg.vertexIndices[4 * (Count div 2)]] := v0;
- list[fg.vertexIndices[4 * (Count div 2) + 1]] := v1;
- list[fg.vertexIndices[4 * (Count div 2) + 2]] := v2;
- end
- else
- begin
- list[fg.vertexIndices[4 * (Count div 2)]] := v0;
- list[fg.vertexIndices[4 * (Count div 2) + 2]] := v1;
- list[fg.vertexIndices[4 * (Count div 2) + 3]] := v2;
- end;
- end;
- else
- Assert(False);
- end;
- Break;
- end;
- end;
- end;
- else
- Assert(False);
- end;
- end;
- procedure TgxMeshObject.SetTriangleData(tri: Integer; list: TgxVectorList; const v0, v1, v2: TVector4f);
- var
- i, LastCount, Count: Integer;
- fg: TgxFGVertexIndexList;
- begin
- case mode of
- momTriangles:
- begin
- list[3 * tri] := v0;
- list[3 * tri + 1] := v1;
- list[3 * tri + 2] := v2;
- end;
- momTriangleStrip:
- begin
- list[tri] := v0;
- list[tri + 1] := v1;
- list[tri + 2] := v2;
- end;
- momFaceGroups:
- begin
- Count := 0;
- for i := 0 to FaceGroups.Count - 1 do
- begin
- LastCount := Count;
- fg := TgxFGVertexIndexList(FaceGroups[i]);
- Count := Count + fg.TriangleCount;
- if Count > tri then
- begin
- Count := tri - LastCount;
- case fg.mode of
- fgmmTriangles, fgmmFlatTriangles:
- begin
- list[fg.vertexIndices[3 * Count]] := v0;
- list[fg.vertexIndices[3 * Count + 1]] := v1;
- list[fg.vertexIndices[3 * Count + 2]] := v2;
- end;
- fgmmTriangleStrip:
- begin
- list[fg.vertexIndices[Count]] := v0;
- list[fg.vertexIndices[Count + 1]] := v1;
- list[fg.vertexIndices[Count + 2]] := v2;
- end;
- fgmmTriangleFan:
- begin
- list[fg.vertexIndices[0]] := v0;
- list[fg.vertexIndices[Count + 1]] := v1;
- list[fg.vertexIndices[Count + 2]] := v2;
- end;
- fgmmQuads:
- begin
- if Count mod 2 = 0 then
- begin
- list[fg.vertexIndices[4 * (Count div 2)]] := v0;
- list[fg.vertexIndices[4 * (Count div 2) + 1]] := v1;
- list[fg.vertexIndices[4 * (Count div 2) + 2]] := v2;
- end
- else
- begin
- list[fg.vertexIndices[4 * (Count div 2)]] := v0;
- list[fg.vertexIndices[4 * (Count div 2) + 2]] := v1;
- list[fg.vertexIndices[4 * (Count div 2) + 3]] := v2;
- end;
- end;
- else
- Assert(False);
- end;
- Break;
- end;
- end;
- end;
- else
- Assert(False);
- end;
- end;
- procedure TgxMeshObject.SetUseVBO(const Value: Boolean);
- var
- i: Integer;
- begin
- if Value = FUseVBO then
- Exit;
- if FUseVBO then
- begin
- FreeAndNil(FVerticesVBO);
- FreeAndNil(FNormalsVBO);
- FreeAndNil(FColorsVBO);
- for i := 0 to high(FTexCoordsVBO) do
- FreeAndNil(FTexCoordsVBO[i]);
- FreeAndNil(FLightmapTexCoordsVBO);
- end;
- FValidBuffers := [];
- FUseVBO := Value;
- end;
- procedure TgxMeshObject.SetValidBuffers(Value: TVBOBuffers);
- var
- i: Integer;
- begin
- if FValidBuffers <> Value then
- begin
- FValidBuffers := Value;
- if Assigned(FVerticesVBO) then
- FVerticesVBO.NotifyChangesOfData;
- if Assigned(FNormalsVBO) then
- FNormalsVBO.NotifyChangesOfData;
- if Assigned(FColorsVBO) then
- FColorsVBO.NotifyChangesOfData;
- for i := 0 to high(FTexCoordsVBO) do
- if Assigned(FTexCoordsVBO[i]) then
- FTexCoordsVBO[i].NotifyChangesOfData;
- if Assigned(FLightmapTexCoordsVBO) then
- FLightmapTexCoordsVBO.NotifyChangesOfData;
- end;
- end;
- procedure TgxMeshObject.BuildTangentSpace(buildBinormals: Boolean = True; buildTangents: Boolean = True);
- var
- i, j: Integer;
- v, n, t: array [0 .. 2] of TAffineVector;
- tangent, binormal: array [0 .. 2] of TVector4f;
- vt, tt: TAffineVector;
- interp, dot: Single;
- procedure SortVertexData(sortidx: Integer);
- begin
- if t[0].v[sortidx] < t[1].v[sortidx] then
- begin
- vt := v[0];
- tt := t[0];
- v[0] := v[1];
- t[0] := t[1];
- v[1] := vt;
- t[1] := tt;
- end;
- if t[0].v[sortidx] < t[2].v[sortidx] then
- begin
- vt := v[0];
- tt := t[0];
- v[0] := v[2];
- t[0] := t[2];
- v[2] := vt;
- t[2] := tt;
- end;
- if t[1].v[sortidx] < t[2].v[sortidx] then
- begin
- vt := v[1];
- tt := t[1];
- v[1] := v[2];
- t[1] := t[2];
- v[2] := vt;
- t[2] := tt;
- end;
- end;
- begin
- Tangents.Clear;
- Binormals.Clear;
- if buildTangents then
- Tangents.Count := Vertices.Count;
- if buildBinormals then
- Binormals.Count := Vertices.Count;
- for i := 0 to TriangleCount - 1 do
- begin
- // Get triangle data
- GetTriangleData(i, Vertices, v[0], v[1], v[2]);
- GetTriangleData(i, normals, n[0], n[1], n[2]);
- GetTriangleData(i, texCoords, t[0], t[1], t[2]);
- for j := 0 to 2 do
- begin
- // Compute tangent
- if buildTangents then
- begin
- SortVertexData(1);
- if (t[2].Y - t[0].Y) = 0 then
- interp := 1
- else
- interp := (t[1].Y - t[0].Y) / (t[2].Y - t[0].Y);
- vt := VectorLerp(v[0], v[2], interp);
- interp := t[0].X + (t[2].X - t[0].X) * interp;
- vt := VectorSubtract(vt, v[1]);
- if t[1].X < interp then
- vt := VectorNegate(vt);
- dot := VectorDotProduct(vt, n[j]);
- vt.X := vt.X - n[j].X * dot;
- vt.Y := vt.Y - n[j].Y * dot;
- vt.Z := vt.Z - n[j].Z * dot;
- tangent[j] := VectorMake(VectorNormalize(vt), 0);
- end;
- // Compute Bi-Normal
- if buildBinormals then
- begin
- SortVertexData(0);
- if (t[2].X - t[0].X) = 0 then
- interp := 1
- else
- interp := (t[1].X - t[0].X) / (t[2].X - t[0].X);
- vt := VectorLerp(v[0], v[2], interp);
- interp := t[0].Y + (t[2].Y - t[0].Y) * interp;
- vt := VectorSubtract(vt, v[1]);
- if t[1].Y < interp then
- vt := VectorNegate(vt);
- dot := VectorDotProduct(vt, n[j]);
- vt.X := vt.X - n[j].X * dot;
- vt.Y := vt.Y - n[j].Y * dot;
- vt.Z := vt.Z - n[j].Z * dot;
- binormal[j] := VectorMake(VectorNormalize(vt), 0);
- end;
- end;
- if buildTangents then
- SetTriangleData(i, Tangents, tangent[0], tangent[1], tangent[2]);
- if buildBinormals then
- SetTriangleData(i, Binormals, binormal[0], binormal[1], binormal[2]);
- end;
- end;
- procedure TgxMeshObject.DeclareArraysToOpenGL(var mrci: TgxRenderContextInfo; evenIfAlreadyDeclared: Boolean = False);
- var
- i: Integer;
- currentMapping: Cardinal;
- lists: array [0 .. 4] of pointer;
- tlists: array of pointer;
- begin
- if evenIfAlreadyDeclared or (not FArraysDeclared) then
- begin
- FillChar(lists, SizeOf(lists), 0);
- SetLength(tlists, FTexCoordsEx.Count);
- // workaround for ATI bug, disable element VBO if
- // inside a display list
- FUseVBO := FUseVBO and not mrci.gxStates.InsideList;
- /// and GL_ARB_vertex_buffer_object
- if not FUseVBO then
- begin
- lists[0] := Vertices.list;
- lists[1] := normals.list;
- lists[2] := Colors.list;
- lists[3] := texCoords.list;
- lists[4] := LightMapTexCoords.list;
- for i := 0 to FTexCoordsEx.Count - 1 do
- tlists[i] := TexCoordsEx[i].list;
- end
- else
- begin
- BufferArrays;
- end;
- if not mrci.ignoreMaterials then
- begin
- if normals.Count > 0 then
- begin
- if FUseVBO then
- FNormalsVBO.Bind;
- glEnableClientState(GL_NORMAL_ARRAY);
- glNormalPointer(GL_FLOAT, 0, lists[1]);
- end
- else
- glDisableClientState(GL_NORMAL_ARRAY);
- if (Colors.Count > 0) and (not mrci.ignoreMaterials) then
- begin
- if FUseVBO then
- FColorsVBO.Bind;
- glEnableClientState(GL_COLOR_ARRAY);
- glColorPointer(4, GL_FLOAT, 0, lists[2]);
- end
- else
- glDisableClientState(GL_COLOR_ARRAY);
- if texCoords.Count > 0 then
- begin
- if FUseVBO then
- FTexCoordsVBO[0].Bind;
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glTexCoordPointer(2, GL_FLOAT, SizeOf(TAffineVector), lists[3]);
- end
- else
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- /// if GL_ARB_multitexture then
- begin
- if LightMapTexCoords.Count > 0 then
- begin
- if FUseVBO then
- FLightmapTexCoordsVBO.Bind;
- glClientActiveTexture(GL_TEXTURE1);
- glTexCoordPointer(2, GL_FLOAT, SizeOf(TAffineVector), lists[4]);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- end;
- for i := 0 to FTexCoordsEx.Count - 1 do
- begin
- if TexCoordsEx[i].Count > 0 then
- begin
- if FUseVBO then
- FTexCoordsVBO[i].Bind;
- glClientActiveTexture(GL_TEXTURE0 + i);
- glTexCoordPointer(4, GL_FLOAT, SizeOf(TVector4f), tlists[i]);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- end;
- end;
- glClientActiveTexture(GL_TEXTURE0);
- end;
- end
- else
- begin
- glDisableClientState(GL_NORMAL_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- end;
- if Vertices.Count > 0 then
- begin
- if FUseVBO then
- FVerticesVBO.Bind;
- glEnableClientState(GL_VERTEX_ARRAY);
- glVertexPointer(3, GL_FLOAT, 0, lists[0]);
- end
- else
- glDisableClientState(GL_VERTEX_ARRAY);
- if (LightMapTexCoords.Count = 0) and not FUseVBO then
- /// and GL_EXT_compiled_vertex_array
- glLockArraysEXT(0, Vertices.Count);
- FLastLightMapIndex := -1;
- FArraysDeclared := True;
- FLightMapArrayEnabled := False;
- if mrci.drawState <> dsPicking then
- FLastXOpenGLTexMapping := xglGetBitWiseMapping;
- end
- else
- begin
- if not mrci.ignoreMaterials and not(mrci.drawState = dsPicking) then
- if texCoords.Count > 0 then
- begin
- currentMapping := xglGetBitWiseMapping;
- if FLastXOpenGLTexMapping <> currentMapping then
- begin
- xglEnableClientState(GL_TEXTURE_COORD_ARRAY);
- xglTexCoordPointer(2, GL_FLOAT, SizeOf(TAffineVector), texCoords.list);
- FLastXOpenGLTexMapping := currentMapping;
- end;
- end;
- end;
- end;
- procedure TgxMeshObject.DisableOpenGLArrays(var mrci: TgxRenderContextInfo);
- var
- i: Integer;
- begin
- if FArraysDeclared then
- begin
- DisableLightMapArray(mrci);
- if (LightMapTexCoords.Count = 0) and not FUseVBO then
- /// and GL_EXT_compiled_vertex_array
- glUnlockArraysEXT;
- if Vertices.Count > 0 then
- glDisableClientState(GL_VERTEX_ARRAY);
- if not mrci.ignoreMaterials then
- begin
- if normals.Count > 0 then
- glDisableClientState(GL_NORMAL_ARRAY);
- if (Colors.Count > 0) and (not mrci.ignoreMaterials) then
- glDisableClientState(GL_COLOR_ARRAY);
- if texCoords.Count > 0 then
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- /// if GL_ARB_multitexture then
- begin
- if LightMapTexCoords.Count > 0 then
- begin
- glClientActiveTexture(GL_TEXTURE1);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- end;
- for i := 0 to FTexCoordsEx.Count - 1 do
- begin
- if TexCoordsEx[i].Count > 0 then
- begin
- glClientActiveTexture(GL_TEXTURE0 + i);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- end;
- end;
- glClientActiveTexture(GL_TEXTURE0);
- end;
- end;
- if FUseVBO then
- begin
- if Vertices.Count > 0 then
- FVerticesVBO.UnBind;
- if normals.Count > 0 then
- FNormalsVBO.UnBind;
- if Colors.Count > 0 then
- FColorsVBO.UnBind;
- if texCoords.Count > 0 then
- FTexCoordsVBO[0].UnBind;
- if LightMapTexCoords.Count > 0 then
- FLightmapTexCoordsVBO.UnBind;
- if FTexCoordsEx.Count > 0 then
- begin
- for i := 0 to FTexCoordsEx.Count - 1 do
- begin
- if TexCoordsEx[i].Count > 0 then
- FTexCoordsVBO[i].UnBind;
- end;
- end;
- end;
- FArraysDeclared := False;
- end;
- end;
- procedure TgxMeshObject.EnableLightMapArray(var mrci: TgxRenderContextInfo);
- begin
- if (not mrci.ignoreMaterials) then
- /// and GL_ARB_multitexture
- begin
- Assert(FArraysDeclared);
- if not FLightMapArrayEnabled then
- begin
- mrci.gxStates.ActiveTexture := 1;
- mrci.gxStates.ActiveTextureEnabled[ttTexture2D] := True;
- mrci.gxStates.ActiveTexture := 0;
- FLightMapArrayEnabled := True;
- end;
- end;
- end;
- procedure TgxMeshObject.DisableLightMapArray(var mrci: TgxRenderContextInfo);
- begin
- if FLightMapArrayEnabled then
- /// and GL_ARB_multitexture
- begin
- mrci.gxStates.ActiveTexture := 1;
- mrci.gxStates.ActiveTextureEnabled[ttTexture2D] := False;
- mrci.gxStates.ActiveTexture := 0;
- FLightMapArrayEnabled := False;
- end;
- end;
- procedure TgxMeshObject.PrepareBuildList(var mrci: TgxRenderContextInfo);
- var
- i: Integer;
- begin
- if (mode = momFaceGroups) and Assigned(mrci.MaterialLibrary) then
- begin
- for i := 0 to FaceGroups.Count - 1 do
- with TgxFaceGroup(FaceGroups.list^[i]) do
- begin
- if MaterialCache <> nil then
- MaterialCache.PrepareBuildList;
- end;
- end;
- end;
- procedure TgxMeshObject.BufferArrays;
- const
- BufferUsage = GL_DYNAMIC_DRAW;
- var
- i: Integer;
- begin
- if Vertices.Count > 0 then
- begin
- if not Assigned(FVerticesVBO) then
- FVerticesVBO := TgxVBOArrayBufferHandle.Create;
- FVerticesVBO.AllocateHandle;
- if FVerticesVBO.IsDataNeedUpdate then
- begin
- FVerticesVBO.BindBufferData(Vertices.list, SizeOf(TAffineVector) * Vertices.Count, BufferUsage);
- FVerticesVBO.NotifyDataUpdated;
- FVerticesVBO.UnBind;
- end;
- Include(FValidBuffers, vbVertices);
- end;
- if normals.Count > 0 then
- begin
- if not Assigned(FNormalsVBO) then
- FNormalsVBO := TgxVBOArrayBufferHandle.Create;
- FNormalsVBO.AllocateHandle;
- if FNormalsVBO.IsDataNeedUpdate then
- begin
- FNormalsVBO.BindBufferData(normals.list, SizeOf(TAffineVector) * normals.Count, BufferUsage);
- FNormalsVBO.NotifyDataUpdated;
- FNormalsVBO.UnBind;
- end;
- Include(FValidBuffers, vbNormals);
- end;
- if Colors.Count > 0 then
- begin
- if not Assigned(FColorsVBO) then
- FColorsVBO := TgxVBOArrayBufferHandle.Create;
- FColorsVBO.AllocateHandle;
- if FColorsVBO.IsDataNeedUpdate then
- begin
- FColorsVBO.BindBufferData(Colors.list, SizeOf(TVector4f) * Colors.Count, BufferUsage);
- FColorsVBO.NotifyDataUpdated;
- FColorsVBO.UnBind;
- end;
- Include(FValidBuffers, vbColors);
- end;
- if texCoords.Count > 0 then
- begin
- if Length(FTexCoordsVBO) < 1 then
- SetLength(FTexCoordsVBO, 1);
- if not Assigned(FTexCoordsVBO[0]) then
- FTexCoordsVBO[0] := TgxVBOArrayBufferHandle.Create;
- FTexCoordsVBO[0].AllocateHandle;
- if FTexCoordsVBO[0].IsDataNeedUpdate then
- begin
- FTexCoordsVBO[0].BindBufferData(texCoords.list, SizeOf(TAffineVector) * texCoords.Count, BufferUsage);
- FTexCoordsVBO[0].NotifyDataUpdated;
- FTexCoordsVBO[0].UnBind;
- end;
- Include(FValidBuffers, vbTexCoords);
- end;
- if LightMapTexCoords.Count > 0 then
- begin
- if not Assigned(FLightmapTexCoordsVBO) then
- FLightmapTexCoordsVBO := TgxVBOArrayBufferHandle.Create;
- FLightmapTexCoordsVBO.AllocateHandle;
- FLightmapTexCoordsVBO.BindBufferData(LightMapTexCoords.list, SizeOf(TAffineVector) * LightMapTexCoords.Count, BufferUsage);
- FLightmapTexCoordsVBO.NotifyDataUpdated;
- FLightmapTexCoordsVBO.UnBind;
- Include(FValidBuffers, vbLightMapTexCoords);
- end;
- if FTexCoordsEx.Count > 0 then
- begin
- if Length(FTexCoordsVBO) < FTexCoordsEx.Count then
- SetLength(FTexCoordsVBO, FTexCoordsEx.Count);
- for i := 0 to FTexCoordsEx.Count - 1 do
- begin
- if TexCoordsEx[i].Count <= 0 then
- continue;
- if not Assigned(FTexCoordsVBO[i]) then
- FTexCoordsVBO[i] := TgxVBOArrayBufferHandle.Create;
- FTexCoordsVBO[i].AllocateHandle;
- if FTexCoordsVBO[i].IsDataNeedUpdate then
- begin
- FTexCoordsVBO[i].BindBufferData(TexCoordsEx[i].list, SizeOf(TVector4f) * TexCoordsEx[i].Count, BufferUsage);
- FTexCoordsVBO[i].NotifyDataUpdated;
- FTexCoordsVBO[i].UnBind;
- end;
- end;
- Include(FValidBuffers, vbTexCoordsEx);
- end;
- /// CheckOpenGLError;
- end;
- procedure TgxMeshObject.BuildList(var mrci: TgxRenderContextInfo);
- var
- i, j, groupID, nbGroups: Integer;
- gotNormals, gotTexCoords, gotColor: Boolean;
- gotTexCoordsEx: array of Boolean;
- libMat: TgxLibMaterial;
- fg: TgxFaceGroup;
- begin
- // Make sure no VBO is bound and states enabled
- FArraysDeclared := False;
- FLastXOpenGLTexMapping := 0;
- gotColor := (Vertices.Count = Colors.Count);
- if gotColor then
- begin
- mrci.gxStates.Enable(stColorMaterial);
- glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
- mrci.gxStates.SetMaterialColors(cmFront, clrBlack, clrGray20, clrGray80, clrBlack, 0);
- mrci.gxStates.SetMaterialColors(cmBack, clrBlack, clrGray20, clrGray80, clrBlack, 0);
- end;
- case mode of
- momTriangles, momTriangleStrip:
- if Vertices.Count > 0 then
- begin
- DeclareArraysToOpenGL(mrci);
- gotNormals := (Vertices.Count = normals.Count);
- gotTexCoords := (Vertices.Count = texCoords.Count);
- SetLength(gotTexCoordsEx, FTexCoordsEx.Count);
- for i := 0 to FTexCoordsEx.Count - 1 do
- gotTexCoordsEx[i] := (TexCoordsEx[i].Count > 0);
- /// and GL_ARB_multitexture;
- if mode = momTriangles then
- glBegin(GL_TRIANGLES)
- else
- glBegin(GL_TRIANGLE_STRIP);
- for i := 0 to Vertices.Count - 1 do
- begin
- if gotNormals then
- glNormal3fv(@normals.list[i]);
- if gotColor then
- glColor4fv(@Colors.list[i]);
- if FTexCoordsEx.Count > 0 then
- begin
- if gotTexCoordsEx[0] then
- glMultiTexCoord4fv(GL_TEXTURE0, @TexCoordsEx[0].list[i])
- else if gotTexCoords then
- glTexCoord2fv(@texCoords.list[i]);
- for j := 1 to FTexCoordsEx.Count - 1 do
- if gotTexCoordsEx[j] then
- glMultiTexCoord4fv(GL_TEXTURE0 + j, @TexCoordsEx[j].list[i]);
- end
- else
- begin
- if gotTexCoords then
- glTexCoord2fv(@texCoords.list[i]);
- end;
- glVertex3fv(@Vertices.list[i]);
- end;
- glEnd;
- end;
- momFaceGroups:
- begin
- if Assigned(mrci.MaterialLibrary) then
- begin
- if moroGroupByMaterial in RenderingOptions then
- begin
- // group-by-material rendering, reduces material switches,
- // but alters rendering order
- groupID := vNextRenderGroupID;
- Inc(vNextRenderGroupID);
- for i := 0 to FaceGroups.Count - 1 do
- begin
- if FaceGroups[i].FRenderGroupID <> groupID then
- begin
- libMat := FaceGroups[i].FMaterialCache;
- if Assigned(libMat) then
- libMat.Apply(mrci);
- repeat
- for j := i to FaceGroups.Count - 1 do
- with FaceGroups[j] do
- begin
- if (FRenderGroupID <> groupID) and (FMaterialCache = libMat) then
- begin
- FRenderGroupID := groupID;
- BuildList(mrci);
- end;
- end;
- until (not Assigned(libMat)) or (not libMat.UnApply(mrci));
- end;
- end;
- end
- else
- begin
- // canonical rendering (regroups only contiguous facegroups)
- i := 0;
- nbGroups := FaceGroups.Count;
- while i < nbGroups do
- begin
- libMat := FaceGroups[i].FMaterialCache;
- if Assigned(libMat) then
- begin
- libMat.Apply(mrci);
- repeat
- j := i;
- while j < nbGroups do
- begin
- fg := FaceGroups[j];
- if fg.MaterialCache <> libMat then
- Break;
- fg.BuildList(mrci);
- Inc(j);
- end;
- until not libMat.UnApply(mrci);
- i := j;
- end
- else
- begin
- FaceGroups[i].BuildList(mrci);
- Inc(i);
- end;
- end;
- end;
- // restore faceculling
- if (stCullFace in mrci.gxStates.States) then
- begin
- if not mrci.bufferFaceCull then
- mrci.gxStates.Disable(stCullFace);
- end
- else
- begin
- if mrci.bufferFaceCull then
- mrci.gxStates.Enable(stCullFace);
- end;
- end
- else
- for i := 0 to FaceGroups.Count - 1 do
- FaceGroups[i].BuildList(mrci);
- end;
- else
- Assert(False);
- end;
- DisableOpenGLArrays(mrci);
- end;
- // ------------------
- // ------------------ TgxMeshObjectList ------------------
- // ------------------
- constructor TgxMeshObjectList.CreateOwned(aOwner: TgxBaseMesh);
- begin
- FOwner := aOwner;
- Create;
- end;
- destructor TgxMeshObjectList.Destroy;
- begin
- Clear;
- inherited;
- end;
- procedure TgxMeshObjectList.ReadFromFiler(reader: TgxVirtualReader);
- var
- i: Integer;
- Mesh: TgxMeshObject;
- begin
- inherited;
- for i := 0 to Count - 1 do
- begin
- Mesh := Items[i];
- Mesh.FOwner := Self;
- if Mesh is TgxSkeletonMeshObject then
- TgxSkeletonMeshObject(Mesh).PrepareBoneMatrixInvertedMeshes;
- end;
- end;
- procedure TgxMeshObjectList.PrepareMaterialLibraryCache(matLib: TgxMaterialLibrary);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TgxMeshObject(list^[i]).PrepareMaterialLibraryCache(matLib);
- end;
- procedure TgxMeshObjectList.DropMaterialLibraryCache;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TgxMeshObject(list^[i]).DropMaterialLibraryCache;
- end;
- procedure TgxMeshObjectList.PrepareBuildList(var mrci: TgxRenderContextInfo);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- with Items[i] do
- if Visible then
- PrepareBuildList(mrci);
- end;
- procedure TgxMeshObjectList.BuildList(var mrci: TgxRenderContextInfo);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- with Items[i] do
- if Visible then
- BuildList(mrci);
- end;
- procedure TgxMeshObjectList.MorphTo(morphTargetIndex: Integer);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- if Items[i] is TgxMorphableMeshObject then
- TgxMorphableMeshObject(Items[i]).MorphTo(morphTargetIndex);
- end;
- procedure TgxMeshObjectList.Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- if Items[i] is TgxMorphableMeshObject then
- TgxMorphableMeshObject(Items[i]).Lerp(morphTargetIndex1, morphTargetIndex2, lerpFactor);
- end;
- function TgxMeshObjectList.MorphTargetCount: Integer;
- var
- i: Integer;
- begin
- Result := MaxInt;
- for i := 0 to Count - 1 do
- if Items[i] is TgxMorphableMeshObject then
- with TgxMorphableMeshObject(Items[i]) do
- if Result > MorphTargets.Count then
- Result := MorphTargets.Count;
- if Result = MaxInt then
- Result := 0;
- end;
- procedure TgxMeshObjectList.Clear;
- var
- i: Integer;
- begin
- DropMaterialLibraryCache;
- for i := 0 to Count - 1 do
- with Items[i] do
- begin
- FOwner := nil;
- Free;
- end;
- inherited;
- end;
- function TgxMeshObjectList.GetMeshObject(Index: Integer): TgxMeshObject;
- begin
- Result := TgxMeshObject(list^[Index]);
- end;
- procedure TgxMeshObjectList.GetExtents(out min, max: TAffineVector);
- var
- i, k: Integer;
- lMin, lMax: TAffineVector;
- const
- cBigValue: Single = 1E30;
- cSmallValue: Single = -1E30;
- begin
- SetVector(min, cBigValue, cBigValue, cBigValue);
- SetVector(max, cSmallValue, cSmallValue, cSmallValue);
- for i := 0 to Count - 1 do
- begin
- GetMeshObject(i).GetExtents(lMin, lMax);
- for k := 0 to 2 do
- begin
- if lMin.v[k] < min.v[k] then
- min.v[k] := lMin.v[k];
- if lMax.v[k] > max.v[k] then
- max.v[k] := lMax.v[k];
- end;
- end;
- end;
- procedure TgxMeshObjectList.Translate(const delta: TAffineVector);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- GetMeshObject(i).Translate(delta);
- end;
- function TgxMeshObjectList.ExtractTriangles(texCoords: TgxAffineVectorList = nil; normals: TgxAffineVectorList = nil)
- : TgxAffineVectorList;
- var
- i: Integer;
- obj: TgxMeshObject;
- objTris: TgxAffineVectorList;
- objTexCoords: TgxAffineVectorList;
- objNormals: TgxAffineVectorList;
- begin
- Result := TgxAffineVectorList.Create;
- if Assigned(texCoords) then
- objTexCoords := TgxAffineVectorList.Create
- else
- objTexCoords := nil;
- if Assigned(normals) then
- objNormals := TgxAffineVectorList.Create
- else
- objNormals := nil;
- try
- for i := 0 to Count - 1 do
- begin
- obj := GetMeshObject(i);
- if not obj.Visible then
- continue;
- objTris := obj.ExtractTriangles(objTexCoords, objNormals);
- try
- Result.Add(objTris);
- if Assigned(texCoords) then
- begin
- texCoords.Add(objTexCoords);
- objTexCoords.Count := 0;
- end;
- if Assigned(normals) then
- begin
- normals.Add(objNormals);
- objNormals.Count := 0;
- end;
- finally
- objTris.Free;
- end;
- end;
- finally
- objTexCoords.Free;
- objNormals.Free;
- end;
- end;
- function TgxMeshObjectList.TriangleCount: Integer;
- var
- i: Integer;
- begin
- Result := 0;
- for i := 0 to Count - 1 do
- Result := Result + Items[i].TriangleCount;
- end;
- procedure TgxMeshObjectList.Prepare;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- Items[i].Prepare;
- end;
- function TgxMeshObjectList.FindMeshByName(MeshName: string): TgxMeshObject;
- var
- i: Integer;
- begin
- Result := nil;
- for i := 0 to Count - 1 do
- if Items[i].Name = MeshName then
- begin
- Result := Items[i];
- Break;
- end;
- end;
- procedure TgxMeshObjectList.BuildTangentSpace(buildBinormals, buildTangents: Boolean);
- var
- i: Integer;
- begin
- if Count <> 0 then
- for i := 0 to Count - 1 do
- GetMeshObject(i).BuildTangentSpace(buildBinormals, buildTangents);
- end;
- function TgxMeshObjectList.GetUseVBO: Boolean;
- var
- i: Integer;
- begin
- Result := True;
- if Count <> 0 then
- for i := 0 to Count - 1 do
- Result := Result and GetMeshObject(i).FUseVBO;
- end;
- procedure TgxMeshObjectList.SetUseVBO(const Value: Boolean);
- var
- i: Integer;
- begin
- if Count <> 0 then
- for i := 0 to Count - 1 do
- GetMeshObject(i).SetUseVBO(Value);
- end;
- // ------------------
- // ------------------ TgxMeshMorphTarget ------------------
- // ------------------
- constructor TgxMeshMorphTarget.CreateOwned(aOwner: TgxMeshMorphTargetList);
- begin
- FOwner := aOwner;
- Create;
- if Assigned(FOwner) then
- FOwner.Add(Self);
- end;
- destructor TgxMeshMorphTarget.Destroy;
- begin
- if Assigned(FOwner) then
- FOwner.Remove(Self);
- inherited;
- end;
- procedure TgxMeshMorphTarget.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- // nothing
- end;
- end;
- procedure TgxMeshMorphTarget.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- // nothing
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- // ------------------
- // ------------------ TgxMeshMorphTargetList ------------------
- // ------------------
- constructor TgxMeshMorphTargetList.CreateOwned(aOwner: TPersistent);
- begin
- FOwner := aOwner;
- Create;
- end;
- destructor TgxMeshMorphTargetList.Destroy;
- begin
- Clear;
- inherited;
- end;
- procedure TgxMeshMorphTargetList.ReadFromFiler(reader: TgxVirtualReader);
- var
- i: Integer;
- begin
- inherited;
- for i := 0 to Count - 1 do
- Items[i].FOwner := Self;
- end;
- procedure TgxMeshMorphTargetList.Translate(const delta: TAffineVector);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- Items[i].Translate(delta);
- end;
- procedure TgxMeshMorphTargetList.Clear;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- with Items[i] do
- begin
- FOwner := nil;
- Free;
- end;
- inherited;
- end;
- function TgxMeshMorphTargetList.GetMeshMorphTarget(Index: Integer): TgxMeshMorphTarget;
- begin
- Result := TgxMeshMorphTarget(list^[Index]);
- end;
- // ------------------
- // ------------------ TgxMorphableMeshObject ------------------
- // ------------------
- constructor TgxMorphableMeshObject.Create;
- begin
- inherited;
- FMorphTargets := TgxMeshMorphTargetList.CreateOwned(Self);
- end;
- destructor TgxMorphableMeshObject.Destroy;
- begin
- FMorphTargets.Free;
- inherited;
- end;
- procedure TgxMorphableMeshObject.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- FMorphTargets.WriteToFiler(writer);
- end;
- end;
- procedure TgxMorphableMeshObject.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- FMorphTargets.ReadFromFiler(reader);
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TgxMorphableMeshObject.Clear;
- begin
- inherited;
- FMorphTargets.Clear;
- end;
- procedure TgxMorphableMeshObject.Translate(const delta: TAffineVector);
- begin
- inherited;
- MorphTargets.Translate(delta);
- ValidBuffers := ValidBuffers - [vbVertices];
- end;
- procedure TgxMorphableMeshObject.MorphTo(morphTargetIndex: Integer);
- begin
- if (morphTargetIndex = 0) and (MorphTargets.Count = 0) then
- Exit;
- Assert(Cardinal(morphTargetIndex) < Cardinal(MorphTargets.Count));
- with MorphTargets[morphTargetIndex] do
- begin
- if Vertices.Count > 0 then
- begin
- Self.Vertices.Assign(Vertices);
- ValidBuffers := ValidBuffers - [vbVertices];
- end;
- if normals.Count > 0 then
- begin
- Self.normals.Assign(normals);
- ValidBuffers := ValidBuffers - [vbNormals];
- end;
- end;
- end;
- procedure TgxMorphableMeshObject.Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single);
- var
- mt1, mt2: TgxMeshMorphTarget;
- begin
- Assert((Cardinal(morphTargetIndex1) < Cardinal(MorphTargets.Count)) and
- (Cardinal(morphTargetIndex2) < Cardinal(MorphTargets.Count)));
- if lerpFactor = 0 then
- MorphTo(morphTargetIndex1)
- else if lerpFactor = 1 then
- MorphTo(morphTargetIndex2)
- else
- begin
- mt1 := MorphTargets[morphTargetIndex1];
- mt2 := MorphTargets[morphTargetIndex2];
- if mt1.Vertices.Count > 0 then
- begin
- Vertices.Lerp(mt1.Vertices, mt2.Vertices, lerpFactor);
- ValidBuffers := ValidBuffers - [vbVertices];
- end;
- if mt1.normals.Count > 0 then
- begin
- normals.Lerp(mt1.normals, mt2.normals, lerpFactor);
- normals.normalize;
- ValidBuffers := ValidBuffers - [vbNormals];
- end;
- end;
- end;
- // ------------------
- // ------------------ TgxSkeletonMeshObject ------------------
- // ------------------
- constructor TgxSkeletonMeshObject.Create;
- begin
- FBoneMatrixInvertedMeshes := TList.Create;
- FBackupInvertedMeshes := TList.Create; // ragdoll
- inherited Create;
- end;
- destructor TgxSkeletonMeshObject.Destroy;
- begin
- Clear;
- FBoneMatrixInvertedMeshes.Free;
- FBackupInvertedMeshes.Free;
- inherited Destroy;
- end;
- procedure TgxSkeletonMeshObject.WriteToFiler(writer: TgxVirtualWriter);
- var
- i: Integer;
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- WriteInteger(FVerticeBoneWeightCount);
- WriteInteger(FBonesPerVertex);
- WriteInteger(FVerticeBoneWeightCapacity);
- for i := 0 to FVerticeBoneWeightCount - 1 do
- Write(FVerticesBonesWeights[i][0], FBonesPerVertex * SizeOf(TgxVertexBoneWeight));
- end;
- end;
- procedure TgxSkeletonMeshObject.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion, i: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- FVerticeBoneWeightCount := ReadInteger;
- FBonesPerVertex := ReadInteger;
- FVerticeBoneWeightCapacity := ReadInteger;
- ResizeVerticesBonesWeights;
- for i := 0 to FVerticeBoneWeightCount - 1 do
- Read(FVerticesBonesWeights[i][0], FBonesPerVertex * SizeOf(TgxVertexBoneWeight));
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TgxSkeletonMeshObject.Clear;
- var
- i: Integer;
- begin
- inherited;
- FVerticeBoneWeightCount := 0;
- FBonesPerVertex := 0;
- ResizeVerticesBonesWeights;
- for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
- TgxBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
- FBoneMatrixInvertedMeshes.Clear;
- end;
- procedure TgxSkeletonMeshObject.SetVerticeBoneWeightCount(const val: Integer);
- begin
- if val <> FVerticeBoneWeightCount then
- begin
- FVerticeBoneWeightCount := val;
- if FVerticeBoneWeightCount > FVerticeBoneWeightCapacity then
- VerticeBoneWeightCapacity := FVerticeBoneWeightCount + 16;
- FLastVerticeBoneWeightCount := FVerticeBoneWeightCount;
- end;
- end;
- procedure TgxSkeletonMeshObject.SetVerticeBoneWeightCapacity(const val: Integer);
- begin
- if val <> FVerticeBoneWeightCapacity then
- begin
- FVerticeBoneWeightCapacity := val;
- ResizeVerticesBonesWeights;
- end;
- end;
- procedure TgxSkeletonMeshObject.SetBonesPerVertex(const val: Integer);
- begin
- if val <> FBonesPerVertex then
- begin
- FBonesPerVertex := val;
- ResizeVerticesBonesWeights;
- end;
- end;
- procedure TgxSkeletonMeshObject.ResizeVerticesBonesWeights;
- var
- n, m, i, j: Integer;
- newArea: PgxVerticesBoneWeights;
- begin
- n := BonesPerVertex * VerticeBoneWeightCapacity;
- if n = 0 then
- begin
- // release everything
- if Assigned(FVerticesBonesWeights) then
- begin
- FreeMem(FVerticesBonesWeights[0]);
- FreeMem(FVerticesBonesWeights);
- FVerticesBonesWeights := nil;
- end;
- end
- else
- begin
- // allocate new area
- GetMem(newArea, VerticeBoneWeightCapacity * SizeOf(PgxVertexBoneWeightArray));
- newArea[0] := AllocMem(n * SizeOf(TgxVertexBoneWeight));
- for i := 1 to VerticeBoneWeightCapacity - 1 do
- newArea[i] := PgxVertexBoneWeightArray(Cardinal(newArea[0]) + Cardinal(i * SizeOf(TgxVertexBoneWeight) * BonesPerVertex));
- // transfer old data
- if FLastVerticeBoneWeightCount < VerticeBoneWeightCount then
- n := FLastVerticeBoneWeightCount
- else
- n := VerticeBoneWeightCount;
- if FLastBonesPerVertex < BonesPerVertex then
- m := FLastBonesPerVertex
- else
- m := BonesPerVertex;
- for i := 0 to n - 1 do
- for j := 0 to m - 1 do
- newArea[i][j] := VerticesBonesWeights[i][j];
- // release old area and switch to new
- if Assigned(FVerticesBonesWeights) then
- begin
- FreeMem(FVerticesBonesWeights[0]);
- FreeMem(FVerticesBonesWeights);
- end;
- FVerticesBonesWeights := newArea;
- end;
- FLastBonesPerVertex := FBonesPerVertex;
- end;
- procedure TgxSkeletonMeshObject.AddWeightedBone(aBoneID: Integer; aWeight: Single);
- begin
- if BonesPerVertex < 1 then
- BonesPerVertex := 1;
- VerticeBoneWeightCount := VerticeBoneWeightCount + 1;
- with VerticesBonesWeights^[VerticeBoneWeightCount - 1]^[0] do
- begin
- BoneID := aBoneID;
- weight := aWeight;
- end;
- end;
- procedure TgxSkeletonMeshObject.AddWeightedBones(const boneIDs: TgxVertexBoneWeightDynArray);
- var
- i: Integer;
- n: Integer;
- begin
- n := Length(boneIDs);
- if BonesPerVertex < n then
- BonesPerVertex := n;
- VerticeBoneWeightCount := VerticeBoneWeightCount + 1;
- for i := 0 to n - 1 do
- begin
- with VerticesBonesWeights^[VerticeBoneWeightCount - 1]^[i] do
- begin
- BoneID := boneIDs[i].BoneID;
- weight := boneIDs[i].weight;
- end;
- end;
- end;
- function TgxSkeletonMeshObject.FindOrAdd(BoneID: Integer; const vertex, normal: TAffineVector): Integer;
- var
- i: Integer;
- dynArray: TgxVertexBoneWeightDynArray;
- begin
- if BonesPerVertex > 1 then
- begin
- SetLength(dynArray, 1);
- dynArray[0].BoneID := BoneID;
- dynArray[0].weight := 1;
- Result := FindOrAdd(dynArray, vertex, normal);
- Exit;
- end;
- Result := -1;
- for i := 0 to Vertices.Count - 1 do
- if (VerticesBonesWeights^[i]^[0].BoneID = BoneID) and VectorEquals(Vertices.list^[i], vertex) and
- VectorEquals(normals.list^[i], normal) then
- begin
- Result := i;
- Break;
- end;
- if Result < 0 then
- begin
- AddWeightedBone(BoneID, 1);
- Vertices.Add(vertex);
- Result := normals.Add(normal);
- end;
- end;
- function TgxSkeletonMeshObject.FindOrAdd(const boneIDs: TgxVertexBoneWeightDynArray; const vertex, normal: TAffineVector)
- : Integer;
- var
- i, j: Integer;
- bonesMatch: Boolean;
- begin
- Result := -1;
- for i := 0 to Vertices.Count - 1 do
- begin
- bonesMatch := True;
- for j := 0 to High(boneIDs) do
- begin
- if (boneIDs[j].BoneID <> VerticesBonesWeights^[i]^[j].BoneID) or (boneIDs[j].weight <> VerticesBonesWeights^[i]^[j].weight)
- then
- begin
- bonesMatch := False;
- Break;
- end;
- end;
- if bonesMatch and VectorEquals(Vertices[i], vertex) and VectorEquals(normals[i], normal) then
- begin
- Result := i;
- Break;
- end;
- end;
- if Result < 0 then
- begin
- AddWeightedBones(boneIDs);
- Vertices.Add(vertex);
- Result := normals.Add(normal);
- end;
- end;
- procedure TgxSkeletonMeshObject.PrepareBoneMatrixInvertedMeshes;
- var
- i, k, boneIndex: Integer;
- invMesh: TgxBaseMeshObject;
- invMat: TMatrix4f;
- Bone: TgxSkeletonBone;
- p: TVector4f;
- begin
- // cleanup existing stuff
- for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
- TgxBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
- FBoneMatrixInvertedMeshes.Clear;
- // calculate
- for k := 0 to BonesPerVertex - 1 do
- begin
- invMesh := TgxBaseMeshObject.Create;
- FBoneMatrixInvertedMeshes.Add(invMesh);
- invMesh.Vertices := Vertices;
- invMesh.normals := normals;
- for i := 0 to Vertices.Count - 1 do
- begin
- boneIndex := VerticesBonesWeights^[i]^[k].BoneID;
- Bone := Owner.Owner.Skeleton.RootBones.BoneByID(boneIndex);
- // transform point
- MakePoint(p, Vertices[i]);
- invMat := Bone.GlobalMatrix;
- InvertMatrix(invMat);
- p := VectorTransform(p, invMat);
- invMesh.Vertices[i] := PAffineVector(@p)^;
- // transform normal
- SetVector(p, normals[i]);
- invMat := Bone.GlobalMatrix;
- invMat.W := NullHmgPoint;
- InvertMatrix(invMat);
- p := VectorTransform(p, invMat);
- invMesh.normals[i] := PAffineVector(@p)^;
- end;
- end;
- end;
- procedure TgxSkeletonMeshObject.BackupBoneMatrixInvertedMeshes; // ragdoll
- var
- i: Integer;
- bm: TgxBaseMeshObject;
- begin
- // cleanup existing stuff
- for i := 0 to FBackupInvertedMeshes.Count - 1 do
- TgxBaseMeshObject(FBackupInvertedMeshes[i]).Free;
- FBackupInvertedMeshes.Clear;
- // copy current stuff
- for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
- begin
- bm := TgxBaseMeshObject.Create;
- bm.Assign(TgxBaseMeshObject(FBoneMatrixInvertedMeshes[i]));
- FBackupInvertedMeshes.Add(bm);
- TgxBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
- end;
- FBoneMatrixInvertedMeshes.Clear;
- end;
- procedure TgxSkeletonMeshObject.RestoreBoneMatrixInvertedMeshes; // ragdoll
- var
- i: Integer;
- bm: TgxBaseMeshObject;
- begin
- // cleanup existing stuff
- for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
- TgxBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
- FBoneMatrixInvertedMeshes.Clear;
- // restore the backup
- for i := 0 to FBackupInvertedMeshes.Count - 1 do
- begin
- bm := TgxBaseMeshObject.Create;
- bm.Assign(TgxBaseMeshObject(FBackupInvertedMeshes[i]));
- FBoneMatrixInvertedMeshes.Add(bm);
- TgxBaseMeshObject(FBackupInvertedMeshes[i]).Free;
- end;
- FBackupInvertedMeshes.Clear;
- end;
- procedure TgxSkeletonMeshObject.ApplyCurrentSkeletonFrame(normalize: Boolean);
- var
- i, j, BoneID: Integer;
- refVertices, refNormals: TgxAffineVectorList;
- n, nt: TVector4f;
- Bone: TgxSkeletonBone;
- Skeleton: TgxSkeleton;
- tempvert, tempnorm: TAffineVector;
- begin
- with TgxBaseMeshObject(FBoneMatrixInvertedMeshes[0]) do
- begin
- refVertices := Vertices;
- refNormals := normals;
- end;
- Skeleton := Owner.Owner.Skeleton;
- n.W := 0;
- if BonesPerVertex = 1 then
- begin
- // simple case, one bone per vertex
- for i := 0 to refVertices.Count - 1 do
- begin
- BoneID := VerticesBonesWeights^[i]^[0].BoneID;
- Bone := Skeleton.BoneByID(BoneID);
- Vertices.list^[i] := VectorTransform(refVertices.list^[i], Bone.GlobalMatrix);
- PAffineVector(@n)^ := refNormals.list^[i];
- nt := VectorTransform(n, Bone.GlobalMatrix);
- normals.list^[i] := PAffineVector(@nt)^;
- end;
- end
- else
- begin
- // multiple bones per vertex
- for i := 0 to refVertices.Count - 1 do
- begin
- Vertices.list^[i] := NullVector;
- normals.list^[i] := NullVector;
- for j := 0 to BonesPerVertex - 1 do
- begin
- with TgxBaseMeshObject(FBoneMatrixInvertedMeshes[j]) do
- begin
- refVertices := Vertices;
- refNormals := normals;
- end;
- tempvert := NullVector;
- tempnorm := NullVector;
- if VerticesBonesWeights^[i]^[j].weight <> 0 then
- begin
- BoneID := VerticesBonesWeights^[i]^[j].BoneID;
- Bone := Skeleton.BoneByID(BoneID);
- CombineVector(tempvert, VectorTransform(refVertices.list^[i], Bone.GlobalMatrix),
- VerticesBonesWeights^[i]^[j].weight);
- PAffineVector(@n)^ := refNormals.list^[i];
- n := VectorTransform(n, Bone.GlobalMatrix);
- CombineVector(tempnorm, PAffineVector(@n)^, VerticesBonesWeights^[i]^[j].weight);
- end;
- AddVector(Vertices.list^[i], tempvert);
- AddVector(normals.list^[i], tempnorm);
- end;
- end;
- end;
- if normalize then
- normals.normalize;
- end;
- // ------------------
- // ------------------ TgxFaceGroup ------------------
- // ------------------
- constructor TgxFaceGroup.CreateOwned(aOwner: TgxFaceGroups);
- begin
- FOwner := aOwner;
- FLightMapIndex := -1;
- Create;
- if Assigned(FOwner) then
- FOwner.Add(Self);
- end;
- destructor TgxFaceGroup.Destroy;
- begin
- if Assigned(FOwner) then
- FOwner.Remove(Self);
- inherited;
- end;
- procedure TgxFaceGroup.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- if FLightMapIndex < 0 then
- begin
- WriteInteger(0); // Archive Version 0
- WriteString(FMaterialName);
- end
- else
- begin
- WriteInteger(1); // Archive Version 1, added FLightMapIndex
- WriteString(FMaterialName);
- WriteInteger(FLightMapIndex);
- end;
- end;
- end;
- procedure TgxFaceGroup.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion in [0 .. 1] then
- with reader do
- begin
- FMaterialName := ReadString;
- if archiveVersion >= 1 then
- FLightMapIndex := ReadInteger
- else
- FLightMapIndex := -1;
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TgxFaceGroup.AttachLightmap(lightMap: TgxTexture; var mrci: TgxRenderContextInfo);
- begin
- /// if GL_ARB_multitexture then
- with lightMap do
- begin
- Assert(Image.NativeTextureTarget = ttTexture2D);
- mrci.gxStates.TextureBinding[1, ttTexture2D] := Handle;
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- mrci.gxStates.ActiveTexture := 0;
- end;
- end;
- procedure TgxFaceGroup.AttachOrDetachLightmap(var mrci: TgxRenderContextInfo);
- var
- libMat: TgxLibMaterial;
- begin
- /// if GL_ARB_multitexture then
- if (not mrci.ignoreMaterials) and Assigned(mrci.LightmapLibrary) then
- begin
- if Owner.Owner.FLastLightMapIndex <> LightMapIndex then
- begin
- Owner.Owner.FLastLightMapIndex := LightMapIndex;
- if LightMapIndex >= 0 then
- begin
- // attach and activate lightmap
- Assert(LightMapIndex < TgxMaterialLibrary(mrci.LightmapLibrary).Materials.Count);
- libMat := TgxMaterialLibrary(mrci.LightmapLibrary).Materials[LightMapIndex];
- AttachLightmap(libMat.Material.Texture, mrci);
- Owner.Owner.EnableLightMapArray(mrci);
- end
- else
- begin
- // desactivate lightmap
- Owner.Owner.DisableLightMapArray(mrci);
- end;
- end;
- end;
- end;
- procedure TgxFaceGroup.PrepareMaterialLibraryCache(matLib: TgxMaterialLibrary);
- begin
- if (FMaterialName <> '') and (matLib <> nil) then
- FMaterialCache := matLib.Materials.GetLibMaterialByName(FMaterialName)
- else
- FMaterialCache := nil;
- end;
- procedure TgxFaceGroup.DropMaterialLibraryCache;
- begin
- FMaterialCache := nil;
- end;
- procedure TgxFaceGroup.AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil;
- aNormals: TgxAffineVectorList = nil);
- begin
- // nothing
- end;
- procedure TgxFaceGroup.Reverse;
- begin
- // nothing
- end;
- procedure TgxFaceGroup.Prepare;
- begin
- // nothing
- end;
- // ------------------
- // ------------------ TgxFGVertexIndexList ------------------
- // ------------------
- constructor TgxFGVertexIndexList.Create;
- begin
- inherited;
- FVertexIndices := TgxIntegerList.Create;
- FMode := fgmmTriangles;
- end;
- destructor TgxFGVertexIndexList.Destroy;
- begin
- FVertexIndices.Free;
- FIndexVBO.Free;
- inherited;
- end;
- procedure TgxFGVertexIndexList.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- FVertexIndices.WriteToFiler(writer);
- WriteInteger(Integer(FMode));
- end;
- end;
- procedure TgxFGVertexIndexList.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- FVertexIndices.ReadFromFiler(reader);
- FMode := TgxFaceGroupMeshMode(ReadInteger);
- InvalidateVBO;
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TgxFGVertexIndexList.SetupVBO;
- const
- BufferUsage = GL_STATIC_DRAW;
- begin
- if not Assigned(FIndexVBO) then
- FIndexVBO := TgxVBOElementArrayHandle.Create;
- FIndexVBO.AllocateHandle;
- if FIndexVBO.IsDataNeedUpdate then
- begin
- FIndexVBO.BindBufferData(vertexIndices.list, SizeOf(Integer) * vertexIndices.Count, BufferUsage);
- FIndexVBO.NotifyDataUpdated;
- end;
- end;
- procedure TgxFGVertexIndexList.SetVertexIndices(const val: TgxIntegerList);
- begin
- FVertexIndices.Assign(val);
- InvalidateVBO;
- end;
- procedure TgxFGVertexIndexList.BuildList(var mrci: TgxRenderContextInfo);
- const
- cFaceGroupMeshModeToOpenGL: array [TgxFaceGroupMeshMode] of Integer = (GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLES,
- GL_TRIANGLE_FAN, GL_QUADS);
- begin
- if vertexIndices.Count = 0 then
- Exit;
- Owner.Owner.DeclareArraysToOpenGL(mrci, False);
- AttachOrDetachLightmap(mrci);
- if Owner.Owner.UseVBO then
- begin
- SetupVBO;
- FIndexVBO.Bind;
- glDrawElements(cFaceGroupMeshModeToOpenGL[mode], vertexIndices.Count, GL_UNSIGNED_INT, nil);
- FIndexVBO.UnBind;
- end
- else
- begin
- glDrawElements(cFaceGroupMeshModeToOpenGL[mode], vertexIndices.Count, GL_UNSIGNED_INT, vertexIndices.list);
- end;
- end;
- procedure TgxFGVertexIndexList.AddToList(Source, destination: TgxAffineVectorList; indices: TgxIntegerList);
- var
- i, n: Integer;
- begin
- if not Assigned(destination) then
- Exit;
- if indices.Count < 3 then
- Exit;
- case mode of
- fgmmTriangles, fgmmFlatTriangles:
- begin
- n := (indices.Count div 3) * 3;
- if Source.Count > 0 then
- begin
- destination.AdjustCapacityToAtLeast(destination.Count + n);
- for i := 0 to n - 1 do
- destination.Add(Source[indices.list^[i]]);
- end
- else
- destination.AddNulls(destination.Count + n);
- end;
- fgmmTriangleStrip:
- begin
- if Source.Count > 0 then
- ConvertStripToList(Source, indices, destination)
- else
- destination.AddNulls(destination.Count + (indices.Count - 2) * 3);
- end;
- fgmmTriangleFan:
- begin
- n := (indices.Count - 2) * 3;
- if Source.Count > 0 then
- begin
- destination.AdjustCapacityToAtLeast(destination.Count + n);
- for i := 2 to vertexIndices.Count - 1 do
- begin
- destination.Add(Source[indices.list^[0]], Source[indices.list^[i - 1]], Source[indices.list^[i]]);
- end;
- end
- else
- destination.AddNulls(destination.Count + n);
- end;
- fgmmQuads:
- begin
- n := indices.Count div 4;
- if Source.Count > 0 then
- begin
- destination.AdjustCapacityToAtLeast(destination.Count + n * 6);
- i := 0;
- while n > 0 do
- begin
- destination.Add(Source[indices.list^[i]], Source[indices.list^[i + 1]], Source[indices.list^[i + 2]]);
- destination.Add(Source[indices.list^[i]], Source[indices.list^[i + 2]], Source[indices.list^[i + 3]]);
- Inc(i, 4);
- Dec(n);
- end;
- end
- else
- destination.AddNulls(destination.Count + n * 6);
- end;
- else
- Assert(False);
- end;
- end;
- procedure TgxFGVertexIndexList.AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil;
- aNormals: TgxAffineVectorList = nil);
- var
- mo: TgxMeshObject;
- begin
- mo := Owner.Owner;
- AddToList(mo.Vertices, aList, vertexIndices);
- AddToList(mo.texCoords, aTexCoords, vertexIndices);
- AddToList(mo.normals, aNormals, vertexIndices);
- InvalidateVBO;
- end;
- function TgxFGVertexIndexList.TriangleCount: Integer;
- begin
- case mode of
- fgmmTriangles, fgmmFlatTriangles:
- Result := vertexIndices.Count div 3;
- fgmmTriangleFan, fgmmTriangleStrip:
- begin
- Result := vertexIndices.Count - 2;
- if Result < 0 then
- Result := 0;
- end;
- fgmmQuads:
- Result := vertexIndices.Count div 2;
- else
- Result := 0;
- Assert(False);
- end;
- end;
- procedure TgxFGVertexIndexList.Reverse;
- begin
- vertexIndices.Reverse;
- InvalidateVBO;
- end;
- procedure TgxFGVertexIndexList.Add(idx: Integer);
- begin
- FVertexIndices.Add(idx);
- InvalidateVBO;
- end;
- procedure TgxFGVertexIndexList.GetExtents(var min, max: TAffineVector);
- var
- i, k: Integer;
- f: Single;
- ref: PFloatArray;
- const
- cBigValue: Single = 1E50;
- cSmallValue: Single = -1E50;
- begin
- SetVector(min, cBigValue, cBigValue, cBigValue);
- SetVector(max, cSmallValue, cSmallValue, cSmallValue);
- for i := 0 to vertexIndices.Count - 1 do
- begin
- ref := Owner.Owner.Vertices.ItemAddress[vertexIndices[i]];
- for k := 0 to 2 do
- begin
- f := ref^[k];
- if f < min.v[k] then
- min.v[k] := f;
- if f > max.v[k] then
- max.v[k] := f;
- end;
- end;
- end;
- procedure TgxFGVertexIndexList.ConvertToList;
- var
- i: Integer;
- bufList: TgxIntegerList;
- begin
- if vertexIndices.Count >= 3 then
- begin
- case mode of
- fgmmTriangleStrip:
- begin
- bufList := TgxIntegerList.Create;
- try
- ConvertStripToList(vertexIndices, bufList);
- vertexIndices := bufList;
- finally
- bufList.Free;
- end;
- FMode := fgmmTriangles;
- end;
- fgmmTriangleFan:
- begin
- bufList := TgxIntegerList.Create;
- try
- for i := 0 to vertexIndices.Count - 3 do
- bufList.Add(vertexIndices[0], vertexIndices[i], vertexIndices[i + 1]);
- vertexIndices := bufList;
- finally
- bufList.Free;
- end;
- FMode := fgmmTriangles;
- end;
- end;
- InvalidateVBO;
- end;
- end;
- function TgxFGVertexIndexList.GetNormal: TAffineVector;
- begin
- if vertexIndices.Count < 3 then
- Result := NullVector
- else
- with Owner.Owner.Vertices do
- CalcPlaneNormal(Items[vertexIndices[0]], Items[vertexIndices[1]], Items[vertexIndices[2]], Result);
- end;
- procedure TgxFGVertexIndexList.InvalidateVBO;
- begin
- if Assigned(FIndexVBO) then
- FIndexVBO.NotifyChangesOfData;
- end;
- // ------------------
- // ------------------ TFGVertexNormalTexIndexList ------------------
- // ------------------
- constructor TFGVertexNormalTexIndexList.Create;
- begin
- inherited;
- FNormalIndices := TgxIntegerList.Create;
- FTexCoordIndices := TgxIntegerList.Create;
- end;
- destructor TFGVertexNormalTexIndexList.Destroy;
- begin
- FTexCoordIndices.Free;
- FNormalIndices.Free;
- inherited;
- end;
- procedure TFGVertexNormalTexIndexList.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- FNormalIndices.WriteToFiler(writer);
- FTexCoordIndices.WriteToFiler(writer);
- end;
- end;
- procedure TFGVertexNormalTexIndexList.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- FNormalIndices.ReadFromFiler(reader);
- FTexCoordIndices.ReadFromFiler(reader);
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TFGVertexNormalTexIndexList.SetNormalIndices(const val: TgxIntegerList);
- begin
- FNormalIndices.Assign(val);
- end;
- procedure TFGVertexNormalTexIndexList.SetTexCoordIndices(const val: TgxIntegerList);
- begin
- FTexCoordIndices.Assign(val);
- end;
- procedure TFGVertexNormalTexIndexList.BuildList(var mrci: TgxRenderContextInfo);
- var
- i: Integer;
- vertexPool: PAffineVectorArray;
- normalPool: PAffineVectorArray;
- texCoordPool: PAffineVectorArray;
- colorPool: PVectorArray;
- normalIdxList, texCoordIdxList, vertexIdxList: PIntegerVector;
- begin
- Assert(((TexCoordIndices.Count = 0) or (vertexIndices.Count <= TexCoordIndices.Count)) and
- ((normalIndices.Count = 0) or (vertexIndices.Count <= normalIndices.Count)));
- vertexPool := Owner.Owner.Vertices.list;
- normalPool := Owner.Owner.normals.list;
- colorPool := Owner.Owner.Colors.list;
- texCoordPool := Owner.Owner.texCoords.list;
- case mode of
- fgmmTriangles, fgmmFlatTriangles:
- glBegin(GL_TRIANGLES);
- fgmmTriangleStrip:
- glBegin(GL_TRIANGLE_STRIP);
- fgmmTriangleFan:
- glBegin(GL_TRIANGLE_FAN);
- else
- Assert(False);
- end;
- vertexIdxList := vertexIndices.list;
- if normalIndices.Count > 0 then
- normalIdxList := normalIndices.list
- else
- normalIdxList := vertexIdxList;
- if TexCoordIndices.Count > 0 then
- texCoordIdxList := TexCoordIndices.list
- else
- texCoordIdxList := vertexIdxList;
- for i := 0 to vertexIndices.Count - 1 do
- begin
- glNormal3fv(@normalPool[normalIdxList^[i]]);
- if Assigned(colorPool) then
- glColor4fv(@colorPool[vertexIdxList^[i]]);
- if Assigned(texCoordPool) then
- glTexCoord2fv(@texCoordPool[texCoordIdxList^[i]]);
- glVertex3fv(@vertexPool[vertexIdxList^[i]]);
- end;
- glEnd;
- end;
- procedure TFGVertexNormalTexIndexList.AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil;
- aNormals: TgxAffineVectorList = nil);
- begin
- AddToList(Owner.Owner.Vertices, aList, vertexIndices);
- AddToList(Owner.Owner.texCoords, aTexCoords, TexCoordIndices);
- AddToList(Owner.Owner.normals, aNormals, normalIndices);
- end;
- procedure TFGVertexNormalTexIndexList.Add(vertexIdx, normalIdx, texCoordIdx: Integer);
- begin
- inherited Add(vertexIdx);
- FNormalIndices.Add(normalIdx);
- FTexCoordIndices.Add(texCoordIdx);
- end;
- // ------------------
- // ------------------ TgxFGIndexTexCoordList ------------------
- // ------------------
- constructor TgxFGIndexTexCoordList.Create;
- begin
- inherited;
- FTexCoords := TgxAffineVectorList.Create;
- end;
- destructor TgxFGIndexTexCoordList.Destroy;
- begin
- FTexCoords.Free;
- inherited;
- end;
- procedure TgxFGIndexTexCoordList.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- FTexCoords.WriteToFiler(writer);
- end;
- end;
- procedure TgxFGIndexTexCoordList.ReadFromFiler(reader: TgxVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- FTexCoords.ReadFromFiler(reader);
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TgxFGIndexTexCoordList.SetTexCoords(const val: TgxAffineVectorList);
- begin
- FTexCoords.Assign(val);
- end;
- procedure TgxFGIndexTexCoordList.BuildList(var mrci: TgxRenderContextInfo);
- var
- i, k: Integer;
- texCoordPool: PAffineVectorArray;
- vertexPool: PAffineVectorArray;
- normalPool: PAffineVectorArray;
- indicesPool: PIntegerArray;
- colorPool: PVectorArray;
- gotColor: Boolean;
- begin
- Assert(vertexIndices.Count = texCoords.Count);
- texCoordPool := texCoords.list;
- vertexPool := Owner.Owner.Vertices.list;
- indicesPool := @vertexIndices.list[0];
- colorPool := @Owner.Owner.Colors.list[0];
- gotColor := (Owner.Owner.Vertices.Count = Owner.Owner.Colors.Count);
- case mode of
- fgmmTriangles:
- glBegin(GL_TRIANGLES);
- fgmmFlatTriangles:
- glBegin(GL_TRIANGLES);
- fgmmTriangleStrip:
- glBegin(GL_TRIANGLE_STRIP);
- fgmmTriangleFan:
- glBegin(GL_TRIANGLE_FAN);
- fgmmQuads:
- glBegin(GL_QUADS);
- else
- Assert(False);
- end;
- if Owner.Owner.normals.Count = Owner.Owner.Vertices.Count then
- begin
- normalPool := Owner.Owner.normals.list;
- for i := 0 to vertexIndices.Count - 1 do
- begin
- glTexCoord2fv(@texCoordPool[i]);
- k := indicesPool[i];
- if gotColor then
- glColor4fv(@colorPool[k]);
- glNormal3fv(@normalPool[k]);
- glVertex3fv(@vertexPool[k]);
- end;
- end
- else
- begin
- for i := 0 to vertexIndices.Count - 1 do
- begin
- glTexCoord2fv(@texCoordPool[i]);
- if gotColor then
- glColor4fv(@colorPool[indicesPool[i]]);
- glVertex3fv(@vertexPool[indicesPool[i]]);
- end;
- end;
- glEnd;
- /// CheckOpenGLError;
- end;
- procedure TgxFGIndexTexCoordList.AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil;
- aNormals: TgxAffineVectorList = nil);
- var
- i, n: Integer;
- texCoordList: TgxAffineVectorList;
- begin
- AddToList(Owner.Owner.Vertices, aList, vertexIndices);
- AddToList(Owner.Owner.normals, aNormals, vertexIndices);
- texCoordList := Self.texCoords;
- case mode of
- fgmmTriangles, fgmmFlatTriangles:
- begin
- if Assigned(aTexCoords) then
- begin
- n := (vertexIndices.Count div 3) * 3;
- aTexCoords.AdjustCapacityToAtLeast(aTexCoords.Count + n);
- for i := 0 to n - 1 do
- aTexCoords.Add(texCoordList[i]);
- end;
- end;
- fgmmTriangleStrip:
- begin
- if Assigned(aTexCoords) then
- ConvertStripToList(aTexCoords, texCoordList);
- end;
- fgmmTriangleFan:
- begin
- if Assigned(aTexCoords) then
- begin
- aTexCoords.AdjustCapacityToAtLeast(aTexCoords.Count + (vertexIndices.Count - 2) * 3);
- for i := 2 to vertexIndices.Count - 1 do
- begin
- aTexCoords.Add(texCoordList[0], texCoordList[i - 1], texCoordList[i]);
- end;
- end;
- end;
- else
- Assert(False);
- end;
- end;
- procedure TgxFGIndexTexCoordList.Add(idx: Integer; const texCoord: TAffineVector);
- begin
- texCoords.Add(texCoord);
- inherited Add(idx);
- end;
- procedure TgxFGIndexTexCoordList.Add(idx: Integer; const s, t: Single);
- begin
- texCoords.Add(s, t, 0);
- inherited Add(idx);
- end;
- // ------------------
- // ------------------ TgxFaceGroups ------------------
- // ------------------
- constructor TgxFaceGroups.CreateOwned(aOwner: TgxMeshObject);
- begin
- FOwner := aOwner;
- Create;
- end;
- destructor TgxFaceGroups.Destroy;
- begin
- Clear;
- inherited;
- end;
- procedure TgxFaceGroups.ReadFromFiler(reader: TgxVirtualReader);
- var
- i: Integer;
- begin
- inherited;
- for i := 0 to Count - 1 do
- Items[i].FOwner := Self;
- end;
- procedure TgxFaceGroups.Clear;
- var
- i: Integer;
- fg: TgxFaceGroup;
- begin
- for i := 0 to Count - 1 do
- begin
- fg := GetFaceGroup(i);
- if Assigned(fg) then
- begin
- fg.FOwner := nil;
- fg.Free;
- end;
- end;
- inherited;
- end;
- function TgxFaceGroups.GetFaceGroup(Index: Integer): TgxFaceGroup;
- begin
- Result := TgxFaceGroup(list^[Index]);
- end;
- procedure TgxFaceGroups.PrepareMaterialLibraryCache(matLib: TgxMaterialLibrary);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TgxFaceGroup(list^[i]).PrepareMaterialLibraryCache(matLib);
- end;
- procedure TgxFaceGroups.DropMaterialLibraryCache;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TgxFaceGroup(list^[i]).DropMaterialLibraryCache;
- end;
- procedure TgxFaceGroups.AddToTriangles(aList: TgxAffineVectorList; aTexCoords: TgxAffineVectorList = nil;
- aNormals: TgxAffineVectorList = nil);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- Items[i].AddToTriangles(aList, aTexCoords, aNormals);
- end;
- function TgxFaceGroups.MaterialLibrary: TgxMaterialLibrary;
- var
- mol: TgxMeshObjectList;
- bm: TgxBaseMesh;
- begin
- if Assigned(Owner) then
- begin
- mol := Owner.Owner;
- if Assigned(mol) then
- begin
- bm := mol.Owner;
- if Assigned(bm) then
- begin
- Result := bm.MaterialLibrary;;
- Exit;
- end;
- end;
- end;
- Result := nil;
- end;
- function CompareMaterials(item1, item2: TObject): Integer;
- function MaterialIsOpaque(fg: TgxFaceGroup): Boolean;
- var
- libMat: TgxLibMaterial;
- begin
- libMat := fg.MaterialCache;
- Result := (not Assigned(libMat)) or (not libMat.Material.Blended);
- end;
- var
- fg1, fg2: TgxFaceGroup;
- opaque1, opaque2: Boolean;
- begin
- fg1 := TgxFaceGroup(item1);
- opaque1 := MaterialIsOpaque(fg1);
- fg2 := TgxFaceGroup(item2);
- opaque2 := MaterialIsOpaque(fg2);
- if opaque1 = opaque2 then
- begin
- Result := CompareStr(fg1.MaterialName, fg2.MaterialName);
- if Result = 0 then
- Result := fg1.LightMapIndex - fg2.LightMapIndex;
- end
- else if opaque1 then
- Result := -1
- else
- Result := 1;
- end;
- procedure TgxFaceGroups.SortByMaterial;
- begin
- PrepareMaterialLibraryCache(Owner.Owner.Owner.MaterialLibrary);
- Sort(@CompareMaterials);
- end;
- // ------------------
- // ------------------ TgxVectorFile ------------------
- // ------------------
- constructor TgxVectorFile.Create(aOwner: TPersistent);
- begin
- Assert(aOwner is TgxBaseMesh);
- inherited;
- end;
- function TgxVectorFile.Owner: TgxBaseMesh;
- begin
- Result := TgxBaseMesh(GetOwner);
- end;
- procedure TgxVectorFile.SetNormalsOrientation(const val: TgxMeshNormalsOrientation);
- begin
- FNormalsOrientation := val;
- end;
- // ------------------
- // ------------------ TgxVectorFileGLSM ------------------
- // ------------------
- class function TgxVectorFileGLSM.Capabilities: TDataFileCapabilities;
- begin
- Result := [dfcRead, dfcWrite];
- end;
- procedure TgxVectorFileGLSM.LoadFromStream(aStream: TStream);
- begin
- Owner.MeshObjects.LoadFromStream(aStream);
- end;
- procedure TgxVectorFileGLSM.SaveToStream(aStream: TStream);
- begin
- Owner.MeshObjects.SaveToStream(aStream);
- end;
- // ------------------
- // ------------------ TgxBaseMesh ------------------
- // ------------------
- constructor TgxBaseMesh.Create(aOwner: TComponent);
- begin
- inherited Create(aOwner);
- if FMeshObjects = nil then
- FMeshObjects := TgxMeshObjectList.CreateOwned(Self);
- if FSkeleton = nil then
- FSkeleton := TgxSkeleton.CreateOwned(Self);
- FUseMeshMaterials := True;
- FAutoCentering := [];
- FAxisAlignedDimensionsCache.X := -1;
- FBaryCenterOffsetChanged := True;
- FAutoScaling := TgxCoordinates.CreateInitialized(Self, XYZWHmgVector, csPoint);
- end;
- destructor TgxBaseMesh.Destroy;
- begin
- FConnectivity.Free;
- DropMaterialLibraryCache;
- FSkeleton.Free;
- FMeshObjects.Free;
- FAutoScaling.Free;
- inherited Destroy;
- end;
- procedure TgxBaseMesh.Assign(Source: TPersistent);
- begin
- if Source is TgxBaseMesh then
- begin
- FSkeleton.Clear;
- FNormalsOrientation := TgxBaseMesh(Source).FNormalsOrientation;
- FMaterialLibrary := TgxBaseMesh(Source).FMaterialLibrary;
- FLightmapLibrary := TgxBaseMesh(Source).FLightmapLibrary;
- FAxisAlignedDimensionsCache := TgxBaseMesh(Source).FAxisAlignedDimensionsCache;
- FBaryCenterOffset := TgxBaseMesh(Source).FBaryCenterOffset;
- FUseMeshMaterials := TgxBaseMesh(Source).FUseMeshMaterials;
- FOverlaySkeleton := TgxBaseMesh(Source).FOverlaySkeleton;
- FIgnoreMissingTextures := TgxBaseMesh(Source).FIgnoreMissingTextures;
- FAutoCentering := TgxBaseMesh(Source).FAutoCentering;
- FAutoScaling.Assign(TgxBaseMesh(Source).FAutoScaling);
- FSkeleton.Assign(TgxBaseMesh(Source).FSkeleton);
- FSkeleton.RootBones.PrepareGlobalMatrices;
- FMeshObjects.Assign(TgxBaseMesh(Source).FMeshObjects);
- end;
- inherited Assign(Source);
- end;
- procedure TgxBaseMesh.LoadFromFile(const filename: string);
- var
- fs: TStream;
- begin
- FLastLoadedFilename := '';
- if filename <> '' then
- begin
- fs := TFileStream.Create(filename, fmOpenRead + fmShareDenyWrite);
- try
- LoadFromStream(filename, fs);
- FLastLoadedFilename := filename;
- finally
- fs.Free;
- end;
- end;
- end;
- procedure TgxBaseMesh.LoadFromStream(const filename: string; aStream: TStream);
- var
- newVectorFile: TgxVectorFile;
- VectorFileClass: TgxVectorFileClass;
- begin
- FLastLoadedFilename := '';
- if filename <> '' then
- begin
- MeshObjects.Clear;
- Skeleton.Clear;
- VectorFileClass := GetVectorFileFormats.FindFromFileName(filename);
- newVectorFile := VectorFileClass.Create(Self);
- try
- newVectorFile.ResourceName := filename;
- PrepareVectorFile(newVectorFile);
- if Assigned(Scene) then
- Scene.BeginUpdate;
- try
- newVectorFile.LoadFromStream(aStream);
- FLastLoadedFilename := filename;
- finally
- if Assigned(Scene) then
- Scene.EndUpdate;
- end;
- finally
- newVectorFile.Free;
- end;
- PerformAutoScaling;
- PerformAutoCentering;
- PrepareMesh;
- end;
- end;
- procedure TgxBaseMesh.SaveToFile(const filename: string);
- var
- fs: TStream;
- begin
- if filename <> '' then
- begin
- fs := TFileStream.Create(filename, fmCreate);
- try
- SaveToStream(filename, fs);
- finally
- fs.Free;
- end;
- end;
- end;
- procedure TgxBaseMesh.SaveToStream(const filename: string; aStream: TStream);
- var
- newVectorFile: TgxVectorFile;
- VectorFileClass: TgxVectorFileClass;
- begin
- if filename <> '' then
- begin
- VectorFileClass := GetVectorFileFormats.FindFromFileName(filename);
- newVectorFile := VectorFileClass.Create(Self);
- try
- newVectorFile.ResourceName := filename;
- PrepareVectorFile(newVectorFile);
- newVectorFile.SaveToStream(aStream);
- finally
- newVectorFile.Free;
- end;
- end;
- end;
- procedure TgxBaseMesh.AddDataFromFile(const filename: string);
- var
- fs: TStream;
- begin
- if filename <> '' then
- begin
- fs := TFileStream.Create(filename, fmOpenRead + fmShareDenyWrite);
- try
- AddDataFromStream(filename, fs);
- finally
- fs.Free;
- end;
- end;
- end;
- procedure TgxBaseMesh.AddDataFromStream(const filename: string; aStream: TStream);
- var
- newVectorFile: TgxVectorFile;
- VectorFileClass: TgxVectorFileClass;
- begin
- if filename <> '' then
- begin
- VectorFileClass := GetVectorFileFormats.FindFromFileName(filename);
- newVectorFile := VectorFileClass.Create(Self);
- newVectorFile.ResourceName := filename;
- PrepareVectorFile(newVectorFile);
- try
- if Assigned(Scene) then
- Scene.BeginUpdate;
- newVectorFile.LoadFromStream(aStream);
- if Assigned(Scene) then
- Scene.EndUpdate;
- finally
- newVectorFile.Free;
- end;
- PrepareMesh;
- end;
- end;
- procedure TgxBaseMesh.GetExtents(out min, max: TAffineVector);
- var
- i, k: Integer;
- lMin, lMax: TAffineVector;
- const
- cBigValue: Single = 1E50;
- cSmallValue: Single = -1E50;
- begin
- SetVector(min, cBigValue, cBigValue, cBigValue);
- SetVector(max, cSmallValue, cSmallValue, cSmallValue);
- for i := 0 to MeshObjects.Count - 1 do
- begin
- TgxMeshObject(MeshObjects[i]).GetExtents(lMin, lMax);
- for k := 0 to 2 do
- begin
- if lMin.v[k] < min.v[k] then
- min.v[k] := lMin.v[k];
- if lMax.v[k] > max.v[k] then
- max.v[k] := lMax.v[k];
- end;
- end;
- end;
- function TgxBaseMesh.GetBarycenter: TAffineVector;
- var
- i, nb: Integer;
- begin
- Result := NullVector;
- nb := 0;
- for i := 0 to MeshObjects.Count - 1 do
- TgxMeshObject(MeshObjects[i]).ContributeToBarycenter(Result, nb);
- if nb > 0 then
- ScaleVector(Result, 1 / nb);
- end;
- function TgxBaseMesh.LastLoadedFilename: string;
- begin
- Result := FLastLoadedFilename;
- end;
- procedure TgxBaseMesh.SetMaterialLibrary(const val: TgxMaterialLibrary);
- begin
- if FMaterialLibrary <> val then
- begin
- if FMaterialLibraryCachesPrepared then
- DropMaterialLibraryCache;
- if Assigned(FMaterialLibrary) then
- begin
- DestroyHandle;
- FMaterialLibrary.RemoveFreeNotification(Self);
- end;
- FMaterialLibrary := val;
- if Assigned(FMaterialLibrary) then
- FMaterialLibrary.FreeNotification(Self);
- StructureChanged;
- end;
- end;
- procedure TgxBaseMesh.SetLightmapLibrary(const val: TgxMaterialLibrary);
- begin
- if FLightmapLibrary <> val then
- begin
- if Assigned(FLightmapLibrary) then
- begin
- DestroyHandle;
- FLightmapLibrary.RemoveFreeNotification(Self);
- end;
- FLightmapLibrary := val;
- if Assigned(FLightmapLibrary) then
- FLightmapLibrary.FreeNotification(Self);
- StructureChanged;
- end;
- end;
- procedure TgxBaseMesh.SetNormalsOrientation(const val: TgxMeshNormalsOrientation);
- begin
- if val <> FNormalsOrientation then
- begin
- FNormalsOrientation := val;
- StructureChanged;
- end;
- end;
- procedure TgxBaseMesh.SetOverlaySkeleton(const val: Boolean);
- begin
- if FOverlaySkeleton <> val then
- begin
- FOverlaySkeleton := val;
- NotifyChange(Self);
- end;
- end;
- procedure TgxBaseMesh.SetAutoScaling(const Value: TgxCoordinates);
- begin
- FAutoScaling.SetPoint(Value.DirectX, Value.DirectY, Value.DirectZ);
- end;
- procedure TgxBaseMesh.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- if Operation = opRemove then
- begin
- if AComponent = FMaterialLibrary then
- MaterialLibrary := nil
- else if AComponent = FLightmapLibrary then
- LightmapLibrary := nil;
- end;
- inherited;
- end;
- function TgxBaseMesh.AxisAlignedDimensionsUnscaled: TVector4f;
- var
- dMin, dMax: TAffineVector;
- begin
- if FAxisAlignedDimensionsCache.X < 0 then
- begin
- MeshObjects.GetExtents(dMin, dMax);
- FAxisAlignedDimensionsCache.X := (dMax.X - dMin.X) / 2;
- FAxisAlignedDimensionsCache.Y := (dMax.Y - dMin.Y) / 2;
- FAxisAlignedDimensionsCache.Z := (dMax.Z - dMin.Z) / 2;
- FAxisAlignedDimensionsCache.W := 0;
- end;
- SetVector(Result, FAxisAlignedDimensionsCache);
- end;
- function TgxBaseMesh.BarycenterOffset: TVector4f;
- var
- dMin, dMax: TAffineVector;
- begin
- if FBaryCenterOffsetChanged then
- begin
- MeshObjects.GetExtents(dMin, dMax);
- FBaryCenterOffset.X := (dMin.X + dMax.X) / 2;
- FBaryCenterOffset.Y := (dMin.Y + dMax.Y) / 2;
- FBaryCenterOffset.Z := (dMin.Z + dMax.Z) / 2;
- FBaryCenterOffset.W := 0;
- FBaryCenterOffsetChanged := False;
- end;
- Result := FBaryCenterOffset;
- end;
- function TgxBaseMesh.BarycenterPosition: TVector4f;
- begin
- Result := VectorAdd(Position.DirectVector, BarycenterOffset);
- end;
- function TgxBaseMesh.BarycenterAbsolutePosition: TVector4f;
- begin
- Result := LocalToAbsolute(BarycenterPosition);
- end;
- procedure TgxBaseMesh.DestroyHandle;
- begin
- if Assigned(FMaterialLibrary) then
- MaterialLibrary.DestroyHandles;
- if Assigned(FLightmapLibrary) then
- LightmapLibrary.DestroyHandles;
- inherited;
- end;
- procedure TgxBaseMesh.PrepareVectorFile(aFile: TgxVectorFile);
- begin
- aFile.NormalsOrientation := NormalsOrientation;
- end;
- procedure TgxBaseMesh.PerformAutoCentering;
- var
- delta, min, max: TAffineVector;
- begin
- if macUseBarycenter in AutoCentering then
- begin
- delta := VectorNegate(GetBarycenter);
- end
- else
- begin
- GetExtents(min, max);
- if macCenterX in AutoCentering then
- delta.X := -0.5 * (min.X + max.X)
- else
- delta.X := 0;
- if macCenterY in AutoCentering then
- delta.Y := -0.5 * (min.Y + max.Y)
- else
- delta.Y := 0;
- if macCenterZ in AutoCentering then
- delta.Z := -0.5 * (min.Z + max.Z)
- else
- delta.Z := 0;
- end;
- MeshObjects.Translate(delta);
- if macRestorePosition in AutoCentering then
- Position.Translate(VectorNegate(delta));
- end;
- procedure TgxBaseMesh.PerformAutoScaling;
- var
- i: Integer;
- vScal: TAffineFltVector;
- begin
- if (FAutoScaling.DirectX <> 1) or (FAutoScaling.DirectY <> 1) or (FAutoScaling.DirectZ <> 1) then
- begin
- MakeVector(vScal, FAutoScaling.DirectX, FAutoScaling.DirectY, FAutoScaling.DirectZ);
- for i := 0 to MeshObjects.Count - 1 do
- begin
- MeshObjects[i].Vertices.Scale(vScal);
- end;
- end;
- end;
- procedure TgxBaseMesh.PrepareMesh;
- begin
- StructureChanged;
- end;
- procedure TgxBaseMesh.PrepareMaterialLibraryCache;
- begin
- if FMaterialLibraryCachesPrepared then
- DropMaterialLibraryCache;
- MeshObjects.PrepareMaterialLibraryCache(FMaterialLibrary);
- FMaterialLibraryCachesPrepared := True;
- end;
- procedure TgxBaseMesh.DropMaterialLibraryCache;
- begin
- if FMaterialLibraryCachesPrepared then
- begin
- MeshObjects.DropMaterialLibraryCache;
- FMaterialLibraryCachesPrepared := False;
- end;
- end;
- procedure TgxBaseMesh.PrepareBuildList(var mrci: TgxRenderContextInfo);
- begin
- MeshObjects.PrepareBuildList(mrci);
- if LightmapLibrary <> nil then
- LightmapLibrary.Materials.PrepareBuildList
- end;
- procedure TgxBaseMesh.SetUseMeshMaterials(const val: Boolean);
- begin
- if val <> FUseMeshMaterials then
- begin
- FUseMeshMaterials := val;
- if FMaterialLibraryCachesPrepared and (not val) then
- DropMaterialLibraryCache;
- StructureChanged;
- end;
- end;
- procedure TgxBaseMesh.BuildList(var rci: TgxRenderContextInfo);
- begin
- MeshObjects.BuildList(rci);
- end;
- procedure TgxBaseMesh.DoRender(var rci: TgxRenderContextInfo; renderSelf, renderChildren: Boolean);
- begin
- if Assigned(LightmapLibrary) then
- xglForbidSecondTextureUnit;
- if renderSelf then
- begin
- // set winding
- case FNormalsOrientation of
- mnoDefault:
- ; // nothing
- mnoInvert:
- rci.gxStates.InvertFrontFace;
- else
- Assert(False);
- end;
- if not rci.ignoreMaterials then
- begin
- if UseMeshMaterials and Assigned(MaterialLibrary) then
- begin
- rci.MaterialLibrary := MaterialLibrary;
- if not FMaterialLibraryCachesPrepared then
- PrepareMaterialLibraryCache;
- end
- else
- rci.MaterialLibrary := nil;
- if Assigned(LightmapLibrary) then
- rci.LightmapLibrary := LightmapLibrary
- else
- rci.LightmapLibrary := nil;
- if rci.amalgamating or not(ListHandleAllocated or (osDirectDraw in ObjectStyle)) then
- PrepareBuildList(rci);
- Material.Apply(rci);
- repeat
- if (osDirectDraw in ObjectStyle) or rci.amalgamating or UseMeshMaterials then
- BuildList(rci)
- else
- rci.gxStates.CallList(GetHandle(rci));
- until not Material.UnApply(rci);
- rci.MaterialLibrary := nil;
- end
- else
- begin
- if (osDirectDraw in ObjectStyle) or rci.amalgamating then
- BuildList(rci)
- else
- rci.gxStates.CallList(GetHandle(rci));
- end;
- if FNormalsOrientation <> mnoDefault then
- rci.gxStates.InvertFrontFace;
- end;
- if Assigned(LightmapLibrary) then
- xglAllowSecondTextureUnit;
- if renderChildren and (Count > 0) then
- Self.renderChildren(0, Count - 1, rci);
- end;
- procedure TgxBaseMesh.StructureChanged;
- begin
- FAxisAlignedDimensionsCache.X := -1;
- FBaryCenterOffsetChanged := True;
- DropMaterialLibraryCache;
- MeshObjects.Prepare;
- inherited;
- end;
- procedure TgxBaseMesh.StructureChangedNoPrepare;
- begin
- inherited StructureChanged;
- end;
- function TgxBaseMesh.RayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
- intersectNormal: PVector4f = nil): Boolean;
- var
- i: Integer;
- tris: TgxAffineVectorList;
- locRayStart, locRayVector, iPoint, iNormal: TVector4f;
- d, minD: Single;
- begin
- // BEWARE! Utterly inefficient implementation!
- tris := MeshObjects.ExtractTriangles;
- try
- SetVector(locRayStart, AbsoluteToLocal(rayStart));
- SetVector(locRayVector, AbsoluteToLocal(rayVector));
- minD := -1;
- i := 0;
- while i < tris.Count do
- begin
- if RayCastTriangleIntersect(locRayStart, locRayVector, tris.list^[i], tris.list^[i + 1], tris.list^[i + 2], @iPoint,
- @iNormal) then
- begin
- d := VectorDistance2(locRayStart, iPoint);
- if (d < minD) or (minD < 0) then
- begin
- minD := d;
- if intersectPoint <> nil then
- intersectPoint^ := iPoint;
- if intersectNormal <> nil then
- intersectNormal^ := iNormal;
- end;
- end;
- Inc(i, 3);
- end;
- finally
- tris.Free;
- end;
- Result := (minD >= 0);
- if Result then
- begin
- if intersectPoint <> nil then
- SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
- if intersectNormal <> nil then
- begin
- SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
- if NormalsOrientation = mnoInvert then
- NegateVector(intersectNormal^);
- end;
- end;
- end;
- function TgxBaseMesh.GenerateSilhouette(const SilhouetteParameters: TgxSilhouetteParameters): TgxSilhouette;
- var
- mc: TgxBaseMeshConnectivity;
- sil: TgxSilhouette;
- begin
- sil := nil;
- if Assigned(FConnectivity) then
- begin
- mc := TgxBaseMeshConnectivity(FConnectivity);
- mc.CreateSilhouette(silhouetteParameters, sil, True);
- end
- else
- begin
- mc := TgxBaseMeshConnectivity.CreateFromMesh(Self);
- try
- mc.CreateSilhouette(silhouetteParameters, sil, True);
- finally
- mc.Free;
- end;
- end;
- Result := sil;
- end;
- procedure TgxBaseMesh.BuildSilhouetteConnectivityData;
- var
- i, j: Integer;
- mo: TgxMeshObject;
- begin
- FreeAndNil(FConnectivity);
- // connectivity data works only on facegroups of TgxFGVertexIndexList class
- for i := 0 to MeshObjects.Count - 1 do
- begin
- mo := (MeshObjects[i] as TgxMeshObject);
- if mo.mode <> momFaceGroups then
- Exit;
- for j := 0 to mo.FaceGroups.Count - 1 do
- if not mo.FaceGroups[j].InheritsFrom(TgxFGVertexIndexList) then
- Exit;
- end;
- FConnectivity := TgxBaseMeshConnectivity.CreateFromMesh(Self);
- end;
- // ------------------
- // ------------------ TgxFreeForm ------------------
- // ------------------
- constructor TgxFreeForm.Create(aOwner: TComponent);
- begin
- inherited;
- // ObjectStyle := [osDirectDraw];
- FUseMeshMaterials := True;
- end;
- destructor TgxFreeForm.Destroy;
- begin
- FOctree.Free;
- inherited Destroy;
- end;
- function TgxFreeForm.GetOctree: TgxOctree;
- begin
- // if not Assigned(FOctree) then //If auto-created, can never use "if Assigned(GLFreeform1.Octree)"
- // FOctree:=TOctree.Create; //moved this code to BuildOctree
- Result := FOctree;
- end;
- procedure TgxFreeForm.BuildOctree(TreeDepth: Integer = 3);
- var
- emin, emax: TAffineVector;
- tl: TgxAffineVectorList;
- begin
- if not Assigned(FOctree) then // moved here from GetOctree
- FOctree := TgxOctree.Create;
- GetExtents(emin, emax);
- tl := MeshObjects.ExtractTriangles;
- try
- with Octree do
- begin
- DisposeTree;
- InitializeTree(emin, emax, tl, TreeDepth);
- end;
- finally
- tl.Free;
- end;
- end;
- function TgxFreeForm.OctreeRayCastIntersect(const rayStart, rayVector: TVector4f; intersectPoint: PVector4f = nil;
- intersectNormal: PVector4f = nil): Boolean;
- var
- locRayStart, locRayVector: TVector4f;
- begin
- Assert(Assigned(FOctree), 'Octree must have been prepared and setup before use.');
- SetVector(locRayStart, AbsoluteToLocal(rayStart));
- SetVector(locRayVector, AbsoluteToLocal(rayVector));
- Result := Octree.RayCastIntersect(locRayStart, locRayVector, intersectPoint, intersectNormal);
- if Result then
- begin
- if intersectPoint <> nil then
- SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
- if intersectNormal <> nil then
- begin
- SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
- if NormalsOrientation = mnoInvert then
- NegateVector(intersectNormal^);
- end;
- end;
- end;
- function TgxFreeForm.OctreePointInMesh(const Point: TVector4f): Boolean;
- const
- cPointRadiusStep = 10000;
- var
- rayStart, rayVector, hitPoint, hitNormal: TVector4f;
- BRad: double;
- HitCount: Integer;
- hitDot: double;
- begin
- Assert(Assigned(FOctree), 'Octree must have been prepared and setup before use.');
- Result := False;
- // Makes calculations sligthly faster by ignoring cases that are guaranteed
- // to be outside the object
- if not PointInObject(Point) then
- Exit;
- BRad := BoundingSphereRadius;
- // This could be a fixed vector, but a fixed vector could have a systemic
- // bug on an non-closed mesh, making it fail constantly for one or several
- // faces.
- rayVector := VectorMake(2 * random - 1, 2 * random - 1, 2 * random - 1);
- rayStart := VectorAdd(VectorScale(rayVector, -BRad), Point);
- HitCount := 0;
- while OctreeRayCastIntersect(rayStart, rayVector, @hitPoint, @hitNormal) do
- begin
- // Are we past our taget?
- if VectorDotProduct(rayVector, VectorSubtract(Point, hitPoint)) < 0 then
- begin
- Result := HitCount > 0;
- Exit;
- end;
- hitDot := VectorDotProduct(hitNormal, rayVector);
- if hitDot < 0 then
- Inc(HitCount)
- else if hitDot > 0 then
- Dec(HitCount);
- // ditDot = 0 is a tricky special case where the ray is just grazing the
- // side of a face - this case means that it doesn't necessarily actually
- // enter the mesh - but it _could_ enter the mesh. If this situation occurs,
- // we should restart the run using a new rayVector - but this implementation
- // currently doesn't.
- // Restart the ray slightly beyond the point it hit the previous face. Note
- // that this step introduces a possible issue with faces that are very close
- rayStart := VectorAdd(hitPoint, VectorScale(rayVector, BRad / cPointRadiusStep));
- end;
- end;
- function TgxFreeForm.OctreeSphereSweepIntersect(const rayStart, rayVector: TVector4f; const velocity, radius: Single;
- intersectPoint: PVector4f = nil; intersectNormal: PVector4f = nil): Boolean;
- var
- locRayStart, locRayVector: TVector4f;
- begin
- Assert(Assigned(FOctree), 'Octree must have been prepared and setup before use.');
- SetVector(locRayStart, AbsoluteToLocal(rayStart));
- SetVector(locRayVector, AbsoluteToLocal(rayVector));
- Result := Octree.SphereSweepIntersect(locRayStart, locRayVector, velocity, radius, intersectPoint, intersectNormal);
- if Result then
- begin
- if intersectPoint <> nil then
- SetVector(intersectPoint^, LocalToAbsolute(intersectPoint^));
- if intersectNormal <> nil then
- begin
- SetVector(intersectNormal^, LocalToAbsolute(intersectNormal^));
- if NormalsOrientation = mnoInvert then
- NegateVector(intersectNormal^);
- end;
- end;
- end;
- function TgxFreeForm.OctreeTriangleIntersect(const v1, v2, v3: TAffineVector): Boolean;
- var
- t1, t2, t3: TAffineVector;
- begin
- Assert(Assigned(FOctree), 'Octree must have been prepared and setup before use.');
- SetVector(t1, AbsoluteToLocal(v1));
- SetVector(t2, AbsoluteToLocal(v2));
- SetVector(t3, AbsoluteToLocal(v3));
- Result := Octree.TriangleIntersect(t1, t2, t3);
- end;
- function TgxFreeForm.OctreeAABBIntersect(const aabb: TAABB; objMatrix, invObjMatrix: TMatrix4f;
- triangles: TgxAffineVectorList = nil): Boolean;
- var
- m1to2, m2to1: TMatrix4f;
- begin
- Assert(Assigned(FOctree), 'Octree must have been prepared and setup before use.');
- // get matrixes needed
- // object to self
- MatrixMultiply(objMatrix, InvAbsoluteMatrix, m1to2);
- // self to object
- MatrixMultiply(AbsoluteMatrix, invObjMatrix, m2to1);
- Result := Octree.AABBIntersect(aabb, m1to2, m2to1, triangles);
- end;
- // ------------------
- // ------------------ TgxActorAnimation ------------------
- // ------------------
- constructor TgxActorAnimation.Create(Collection: TCollection);
- begin
- inherited Create(Collection);
- end;
- destructor TgxActorAnimation.Destroy;
- begin
- with (Collection as TgxActorAnimations).FOwner do
- if FTargetSmoothAnimation = Self then
- FTargetSmoothAnimation := nil;
- inherited Destroy;
- end;
- procedure TgxActorAnimation.Assign(Source: TPersistent);
- begin
- if Source is TgxActorAnimation then
- begin
- FName := TgxActorAnimation(Source).FName;
- FStartFrame := TgxActorAnimation(Source).FStartFrame;
- FEndFrame := TgxActorAnimation(Source).FEndFrame;
- FReference := TgxActorAnimation(Source).FReference;
- end
- else
- inherited;
- end;
- function TgxActorAnimation.GetDisplayName: string;
- begin
- Result := Format('%d - %s [%d - %d]', [Index, Name, startFrame, endFrame]);
- end;
- function TgxActorAnimation.FrameCount: Integer;
- begin
- case reference of
- aarMorph:
- Result := TgxActorAnimations(Collection).FOwner.MeshObjects.MorphTargetCount;
- aarSkeleton:
- Result := TgxActorAnimations(Collection).FOwner.Skeleton.Frames.Count;
- else
- Result := 0;
- Assert(False);
- end;
- end;
- procedure TgxActorAnimation.SetStartFrame(const val: Integer);
- var
- m: Integer;
- begin
- if val < 0 then
- FStartFrame := 0
- else
- begin
- m := FrameCount;
- if val >= m then
- FStartFrame := m - 1
- else
- FStartFrame := val;
- end;
- if FStartFrame > FEndFrame then
- FEndFrame := FStartFrame;
- end;
- procedure TgxActorAnimation.SetEndFrame(const val: Integer);
- var
- m: Integer;
- begin
- if val < 0 then
- FEndFrame := 0
- else
- begin
- m := FrameCount;
- if val >= m then
- FEndFrame := m - 1
- else
- FEndFrame := val;
- end;
- if FStartFrame > FEndFrame then
- FStartFrame := FEndFrame;
- end;
- procedure TgxActorAnimation.SetReference(val: TgxActorAnimationReference);
- begin
- if val <> FReference then
- begin
- FReference := val;
- startFrame := startFrame;
- endFrame := endFrame;
- end;
- end;
- procedure TgxActorAnimation.SetAsString(const val: string);
- var
- sl: TStringList;
- begin
- sl := TStringList.Create;
- try
- sl.CommaText := val;
- Assert(sl.Count >= 3);
- FName := sl[0];
- FStartFrame := StrToInt(sl[1]);
- FEndFrame := StrToInt(sl[2]);
- if sl.Count = 4 then
- begin
- if LowerCase(sl[3]) = 'morph' then
- reference := aarMorph
- else if LowerCase(sl[3]) = 'skeleton' then
- reference := aarSkeleton
- else
- Assert(False);
- end
- else
- reference := aarMorph;
- finally
- sl.Free;
- end;
- end;
- function TgxActorAnimation.GetAsString: string;
- const
- cAARToString: array [aarMorph .. aarSkeleton] of string = ('morph', 'skeleton');
- begin
- Result := Format('"%s",%d,%d,%s', [FName, FStartFrame, FEndFrame, cAARToString[reference]]);
- end;
- function TgxActorAnimation.OwnerActor: TgxActor;
- begin
- Result := ((Collection as TgxActorAnimations).GetOwner as TgxActor);
- end;
- procedure TgxActorAnimation.MakeSkeletalTranslationStatic;
- begin
- OwnerActor.Skeleton.MakeSkeletalTranslationStatic(startFrame, endFrame);
- end;
- procedure TgxActorAnimation.MakeSkeletalRotationDelta;
- begin
- OwnerActor.Skeleton.MakeSkeletalRotationDelta(startFrame, endFrame);
- end;
- // ------------------
- // ------------------ TgxActorAnimations ------------------
- // ------------------
- constructor TgxActorAnimations.Create(aOwner: TgxActor);
- begin
- FOwner := aOwner;
- inherited Create(TgxActorAnimation);
- end;
- function TgxActorAnimations.GetOwner: TPersistent;
- begin
- Result := FOwner;
- end;
- procedure TgxActorAnimations.SetItems(Index: Integer; const val: TgxActorAnimation);
- begin
- inherited Items[index] := val;
- end;
- function TgxActorAnimations.GetItems(Index: Integer): TgxActorAnimation;
- begin
- Result := TgxActorAnimation(inherited Items[index]);
- end;
- function TgxActorAnimations.Last: TgxActorAnimation;
- begin
- if Count > 0 then
- Result := TgxActorAnimation(inherited Items[Count - 1])
- else
- Result := nil;
- end;
- function TgxActorAnimations.Add: TgxActorAnimation;
- begin
- Result := (inherited Add) as TgxActorAnimation;
- end;
- function TgxActorAnimations.FindItemID(ID: Integer): TgxActorAnimation;
- begin
- Result := (inherited FindItemID(ID)) as TgxActorAnimation;
- end;
- function TgxActorAnimations.FindName(const aName: string): TgxActorAnimation;
- var
- i: Integer;
- begin
- Result := nil;
- for i := 0 to Count - 1 do
- if CompareText(Items[i].Name, aName) = 0 then
- begin
- Result := Items[i];
- Break;
- end;
- end;
- function TgxActorAnimations.FindFrame(aFrame: Integer; aReference: TgxActorAnimationReference): TgxActorAnimation;
- var
- i: Integer;
- begin
- Result := nil;
- for i := 0 to Count - 1 do
- with Items[i] do
- if (startFrame <= aFrame) and (endFrame >= aFrame) and (reference = aReference) then
- begin
- Result := Items[i];
- Break;
- end;
- end;
- procedure TgxActorAnimations.SetToStrings(aStrings: TStrings);
- var
- i: Integer;
- begin
- with aStrings do
- begin
- BeginUpdate;
- Clear;
- for i := 0 to Self.Count - 1 do
- Add(Self.Items[i].Name);
- EndUpdate;
- end;
- end;
- procedure TgxActorAnimations.SaveToStream(aStream: TStream);
- var
- i: Integer;
- begin
- WriteCRLFString(aStream, cAAFHeader);
- WriteCRLFString(aStream, AnsiString(IntToStr(Count)));
- for i := 0 to Count - 1 do
- WriteCRLFString(aStream, AnsiString(Items[i].AsString));
- end;
- procedure TgxActorAnimations.LoadFromStream(aStream: TStream);
- var
- i, n: Integer;
- begin
- Clear;
- if ReadCRLFString(aStream) <> cAAFHeader then
- Assert(False);
- n := StrToInt(string(ReadCRLFString(aStream)));
- for i := 0 to n - 1 do
- Add.AsString := string(ReadCRLFString(aStream));
- end;
- procedure TgxActorAnimations.SaveToFile(const filename: string);
- var
- fs: TStream;
- begin
- fs := TFileStream.Create(filename, fmCreate);
- try
- SaveToStream(fs);
- finally
- fs.Free;
- end;
- end;
- procedure TgxActorAnimations.LoadFromFile(const filename: string);
- var
- fs: TStream;
- begin
- fs := TFileStream.Create(filename, fmOpenRead + fmShareDenyWrite);
- try
- LoadFromStream(fs);
- finally
- fs.Free;
- end;
- end;
- // ------------------
- // ------------------ TgxBaseAnimationControler ------------------
- // ------------------
- constructor TgxBaseAnimationControler.Create(aOwner: TComponent);
- begin
- inherited Create(aOwner);
- FEnabled := True;
- end;
- destructor TgxBaseAnimationControler.Destroy;
- begin
- SetActor(nil);
- inherited Destroy;
- end;
- procedure TgxBaseAnimationControler.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- if (AComponent = FActor) and (Operation = opRemove) then
- SetActor(nil);
- inherited;
- end;
- procedure TgxBaseAnimationControler.DoChange;
- begin
- if Assigned(FActor) then
- FActor.NotifyChange(Self);
- end;
- procedure TgxBaseAnimationControler.SetEnabled(const val: Boolean);
- begin
- if val <> FEnabled then
- begin
- FEnabled := val;
- if Assigned(FActor) then
- DoChange;
- end;
- end;
- procedure TgxBaseAnimationControler.SetActor(const val: TgxActor);
- begin
- if FActor <> val then
- begin
- if Assigned(FActor) then
- FActor.UnRegisterControler(Self);
- FActor := val;
- if Assigned(FActor) then
- begin
- FActor.RegisterControler(Self);
- DoChange;
- end;
- end;
- end;
- function TgxBaseAnimationControler.Apply(var lerpInfo: TGXBlendedLerpInfo): Boolean;
- begin
- // virtual
- Result := False;
- end;
- // ------------------
- // ------------------ TgxAnimationControler ------------------
- // ------------------
- procedure TgxAnimationControler.DoChange;
- begin
- if AnimationName <> '' then
- inherited;
- end;
- procedure TgxAnimationControler.SetAnimationName(const val: TgxActorAnimationName);
- begin
- if FAnimationName <> val then
- begin
- FAnimationName := val;
- DoChange;
- end;
- end;
- procedure TgxAnimationControler.SetRatio(const val: Single);
- begin
- if FRatio <> val then
- begin
- FRatio := ClampValue(val, 0, 1);
- DoChange;
- end;
- end;
- function TgxAnimationControler.Apply(var lerpInfo: TGXBlendedLerpInfo): Boolean;
- var
- anim: TgxActorAnimation;
- baseDelta: Integer;
- begin
- if not Enabled then
- begin
- Result := False;
- Exit;
- end;
- anim := Actor.Animations.FindName(AnimationName);
- Result := (anim <> nil);
- if not Result then
- Exit;
- with lerpInfo do
- begin
- if Ratio = 0 then
- begin
- frameIndex1 := anim.startFrame;
- frameIndex2 := frameIndex1;
- lerpFactor := 0;
- end
- else if Ratio = 1 then
- begin
- frameIndex1 := anim.endFrame;
- frameIndex2 := frameIndex1;
- lerpFactor := 0;
- end
- else
- begin
- baseDelta := anim.endFrame - anim.startFrame;
- lerpFactor := anim.startFrame + baseDelta * Ratio;
- frameIndex1 := Trunc(lerpFactor);
- frameIndex2 := frameIndex1 + 1;
- lerpFactor := Frac(lerpFactor);
- end;
- weight := 1;
- externalRotations := nil;
- externalQuaternions := nil;
- end;
- end;
- // ------------------
- // ------------------ TgxActor ------------------
- // ------------------
- constructor TgxActor.Create(aOwner: TComponent);
- begin
- inherited Create(aOwner);
- ObjectStyle := ObjectStyle + [osDirectDraw];
- FFrameInterpolation := afpLinear;
- FAnimationMode := aamNone;
- FInterval := 100; // 10 animation frames per second
- FAnimations := TgxActorAnimations.Create(Self);
- FControlers := nil; // created on request
- FOptions := cDefaultActorOptions;
- end;
- destructor TgxActor.Destroy;
- begin
- inherited Destroy;
- FControlers.Free;
- FAnimations.Free;
- end;
- procedure TgxActor.Assign(Source: TPersistent);
- begin
- inherited Assign(Source);
- if Source is TgxActor then
- begin
- FAnimations.Assign(TgxActor(Source).FAnimations);
- FAnimationMode := TgxActor(Source).FAnimationMode;
- Synchronize(TgxActor(Source));
- end;
- end;
- procedure TgxActor.RegisterControler(aControler: TgxBaseAnimationControler);
- begin
- if not Assigned(FControlers) then
- FControlers := TList.Create;
- FControlers.Add(aControler);
- FreeNotification(aControler);
- end;
- procedure TgxActor.UnRegisterControler(aControler: TgxBaseAnimationControler);
- begin
- Assert(Assigned(FControlers));
- FControlers.Remove(aControler);
- RemoveFreeNotification(aControler);
- if FControlers.Count = 0 then
- FreeAndNil(FControlers);
- end;
- procedure TgxActor.SetCurrentFrame(val: Integer);
- begin
- if val <> CurrentFrame then
- begin
- if val > FrameCount - 1 then
- FCurrentFrame := FrameCount - 1
- else if val < 0 then
- FCurrentFrame := 0
- else
- FCurrentFrame := val;
- FCurrentFrameDelta := 0;
- case AnimationMode of
- aamPlayOnce:
- if (CurrentFrame = endFrame) and (FTargetSmoothAnimation = nil) then
- FAnimationMode := aamNone;
- aamBounceForward:
- if CurrentFrame = endFrame then
- FAnimationMode := aamBounceBackward;
- aamBounceBackward:
- if CurrentFrame = startFrame then
- FAnimationMode := aamBounceForward;
- end;
- StructureChanged;
- if Assigned(FOnFrameChanged) then
- FOnFrameChanged(Self);
- end;
- end;
- procedure TgxActor.SetCurrentFrameDirect(const Value: Integer);
- begin
- FCurrentFrame := Value;
- end;
- procedure TgxActor.SetStartFrame(val: Integer);
- begin
- if (val >= 0) and (val < FrameCount) and (val <> startFrame) then
- FStartFrame := val;
- if endFrame < startFrame then
- FEndFrame := FStartFrame;
- if CurrentFrame < startFrame then
- CurrentFrame := FStartFrame;
- end;
- procedure TgxActor.SetEndFrame(val: Integer);
- begin
- if (val >= 0) and (val < FrameCount) and (val <> endFrame) then
- FEndFrame := val;
- if CurrentFrame > endFrame then
- CurrentFrame := FEndFrame;
- end;
- procedure TgxActor.SetReference(val: TgxActorAnimationReference);
- begin
- if val <> reference then
- begin
- FReference := val;
- startFrame := startFrame;
- endFrame := endFrame;
- CurrentFrame := CurrentFrame;
- StructureChanged;
- end;
- end;
- procedure TgxActor.SetAnimations(const val: TgxActorAnimations);
- begin
- FAnimations.Assign(val);
- end;
- function TgxActor.StoreAnimations: Boolean;
- begin
- Result := (FAnimations.Count > 0);
- end;
- procedure TgxActor.SetOptions(const val: TgxActorOptions);
- begin
- if val <> FOptions then
- begin
- FOptions := val;
- StructureChanged;
- end;
- end;
- function TgxActor.NextFrameIndex: Integer;
- begin
- case AnimationMode of
- aamLoop, aamBounceForward:
- begin
- if FTargetSmoothAnimation <> nil then
- Result := FTargetSmoothAnimation.startFrame
- else
- begin
- Result := CurrentFrame + 1;
- if Result > endFrame then
- begin
- Result := startFrame + (Result - endFrame - 1);
- if Result > endFrame then
- Result := endFrame;
- end;
- end;
- end;
- aamNone, aamPlayOnce:
- begin
- if FTargetSmoothAnimation <> nil then
- Result := FTargetSmoothAnimation.startFrame
- else
- begin
- Result := CurrentFrame + 1;
- if Result > endFrame then
- Result := endFrame;
- end;
- end;
- aamBounceBackward, aamLoopBackward:
- begin
- if FTargetSmoothAnimation <> nil then
- Result := FTargetSmoothAnimation.startFrame
- else
- begin
- Result := CurrentFrame - 1;
- if Result < startFrame then
- begin
- Result := endFrame - (startFrame - Result - 1);
- if Result < startFrame then
- Result := startFrame;
- end;
- end;
- end;
- aamExternal:
- Result := CurrentFrame; // Do nothing
- else
- Result := CurrentFrame;
- Assert(False);
- end;
- end;
- procedure TgxActor.NextFrame(nbSteps: Integer = 1);
- var
- n: Integer;
- begin
- n := nbSteps;
- while n > 0 do
- begin
- CurrentFrame := NextFrameIndex;
- Dec(n);
- if Assigned(FOnEndFrameReached) and (CurrentFrame = endFrame) then
- FOnEndFrameReached(Self);
- if Assigned(FOnStartFrameReached) and (CurrentFrame = startFrame) then
- FOnStartFrameReached(Self);
- end;
- end;
- procedure TgxActor.PrevFrame(nbSteps: Integer = 1);
- var
- Value: Integer;
- begin
- Value := FCurrentFrame - nbSteps;
- if Value < FStartFrame then
- begin
- Value := FEndFrame - (FStartFrame - Value);
- if Value < FStartFrame then
- Value := FStartFrame;
- end;
- CurrentFrame := Value;
- end;
- procedure TgxActor.DoAnimate();
- var
- i, k: Integer;
- nextFrameIdx: Integer;
- lerpInfos: array of TGXBlendedLerpInfo;
- begin
- nextFrameIdx := NextFrameIndex;
- case reference of
- aarMorph:
- if nextFrameIdx >= 0 then
- begin
- case FrameInterpolation of
- afpLinear:
- MeshObjects.Lerp(CurrentFrame, nextFrameIdx, CurrentFrameDelta)
- else
- MeshObjects.MorphTo(CurrentFrame);
- end;
- end;
- aarSkeleton:
- if Skeleton.Frames.Count > 0 then
- begin
- if Assigned(FControlers) and (AnimationMode <> aamExternal) then
- begin
- // Blended Skeletal Lerping
- SetLength(lerpInfos, FControlers.Count + 1);
- if nextFrameIdx >= 0 then
- begin
- case FrameInterpolation of
- afpLinear:
- with lerpInfos[0] do
- begin
- frameIndex1 := CurrentFrame;
- frameIndex2 := nextFrameIdx;
- lerpFactor := CurrentFrameDelta;
- weight := 1;
- end;
- else
- with lerpInfos[0] do
- begin
- frameIndex1 := CurrentFrame;
- frameIndex2 := CurrentFrame;
- lerpFactor := 0;
- weight := 1;
- end;
- end;
- end
- else
- begin
- with lerpInfos[0] do
- begin
- frameIndex1 := CurrentFrame;
- frameIndex2 := CurrentFrame;
- lerpFactor := 0;
- weight := 1;
- end;
- end;
- k := 1;
- for i := 0 to FControlers.Count - 1 do
- if TgxBaseAnimationControler(FControlers[i]).Apply(lerpInfos[k]) then
- Inc(k);
- SetLength(lerpInfos, k);
- Skeleton.BlendedLerps(lerpInfos);
- end
- else if (nextFrameIdx >= 0) and (AnimationMode <> aamExternal) then
- begin
- // Single Skeletal Lerp
- case FrameInterpolation of
- afpLinear:
- Skeleton.Lerp(CurrentFrame, nextFrameIdx, CurrentFrameDelta);
- else
- Skeleton.SetCurrentFrame(Skeleton.Frames[CurrentFrame]);
- end;
- end;
- Skeleton.MorphMesh(aoSkeletonNormalizeNormals in Options);
- end;
- aarNone:
- ; // do nothing
- end;
- end;
- procedure TgxActor.BuildList(var rci: TgxRenderContextInfo);
- begin
- DoAnimate;
- inherited;
- if OverlaySkeleton then
- begin
- rci.gxStates.Disable(stDepthTest);
- Skeleton.RootBones.BuildList(rci);
- end;
- end;
- procedure TgxActor.PrepareMesh;
- begin
- FStartFrame := 0;
- FEndFrame := FrameCount - 1;
- FCurrentFrame := 0;
- if Assigned(FOnFrameChanged) then
- FOnFrameChanged(Self);
- inherited;
- end;
- procedure TgxActor.PrepareBuildList(var mrci: TgxRenderContextInfo);
- begin
- // no preparation needed for actors, they don't use buildlists
- end;
- function TgxActor.FrameCount: Integer;
- begin
- case reference of
- aarMorph:
- Result := MeshObjects.MorphTargetCount;
- aarSkeleton:
- Result := Skeleton.Frames.Count;
- aarNone:
- Result := 0;
- else
- Result := 0;
- Assert(False);
- end;
- end;
- procedure TgxActor.DoProgress(const progressTime: TgxProgressTimes);
- var
- fDelta: Single;
- begin
- inherited;
- if (AnimationMode <> aamNone) and (Interval > 0) then
- begin
- if (startFrame <> endFrame) and (FrameCount > 1) then
- begin
- FCurrentFrameDelta := FCurrentFrameDelta + (progressTime.deltaTime * 1000) / FInterval;
- if FCurrentFrameDelta > 1 then
- begin
- if Assigned(FTargetSmoothAnimation) then
- begin
- SwitchToAnimation(FTargetSmoothAnimation);
- FTargetSmoothAnimation := nil;
- end;
- // we need to step on
- fDelta := Frac(FCurrentFrameDelta);
- NextFrame(Trunc(FCurrentFrameDelta));
- FCurrentFrameDelta := fDelta;
- StructureChanged;
- end
- else if FrameInterpolation <> afpNone then
- StructureChanged;
- end;
- end;
- end;
- procedure TgxActor.LoadFromStream(const filename: string; aStream: TStream);
- begin
- if filename <> '' then
- begin
- Animations.Clear;
- inherited LoadFromStream(filename, aStream);
- end;
- end;
- procedure TgxActor.SwitchToAnimation(const AnimationName: string; smooth: Boolean = False);
- begin
- SwitchToAnimation(Animations.FindName(AnimationName), smooth);
- end;
- procedure TgxActor.SwitchToAnimation(animationIndex: Integer; smooth: Boolean = False);
- begin
- if (animationIndex >= 0) and (animationIndex < Animations.Count) then
- SwitchToAnimation(Animations[animationIndex], smooth);
- end;
- procedure TgxActor.SwitchToAnimation(anAnimation: TgxActorAnimation; smooth: Boolean = False);
- begin
- if Assigned(anAnimation) then
- begin
- if smooth then
- begin
- FTargetSmoothAnimation := anAnimation;
- FCurrentFrameDelta := 0;
- end
- else
- begin
- reference := anAnimation.reference;
- startFrame := anAnimation.startFrame;
- endFrame := anAnimation.endFrame;
- CurrentFrame := startFrame;
- end;
- end;
- end;
- function TgxActor.CurrentAnimation: string;
- var
- aa: TgxActorAnimation;
- begin
- aa := Animations.FindFrame(CurrentFrame, reference);
- if Assigned(aa) then
- Result := aa.Name
- else
- Result := '';
- end;
- procedure TgxActor.Synchronize(referenceActor: TgxActor);
- begin
- if Assigned(referenceActor) then
- begin
- if referenceActor.startFrame < FrameCount then
- FStartFrame := referenceActor.startFrame;
- if referenceActor.endFrame < FrameCount then
- FEndFrame := referenceActor.endFrame;
- FReference := referenceActor.reference;
- if referenceActor.CurrentFrame < FrameCount then
- FCurrentFrame := referenceActor.CurrentFrame;
- FCurrentFrameDelta := referenceActor.CurrentFrameDelta;
- FAnimationMode := referenceActor.AnimationMode;
- FFrameInterpolation := referenceActor.FrameInterpolation;
- if referenceActor.FTargetSmoothAnimation <> nil then
- FTargetSmoothAnimation := Animations.FindName(referenceActor.FTargetSmoothAnimation.Name)
- else
- FTargetSmoothAnimation := nil;
- if (Skeleton.Frames.Count > 0) and (referenceActor.Skeleton.Frames.Count > 0) then
- Skeleton.Synchronize(referenceActor.Skeleton);
- end;
- end;
- function TgxActor.isSwitchingAnimation: Boolean;
- begin
- Result := FTargetSmoothAnimation <> nil;
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterVectorFileFormat('glsm', 'GXScene Mesh', TgxVectorFileGLSM);
- RegisterClasses([TgxFreeForm, TgxActor, TgxSkeleton, TgxSkeletonFrame, TgxSkeletonBone, TgxSkeletonMeshObject, TgxMeshObject,
- TgxSkeletonFrameList, TgxMeshMorphTarget, TgxMorphableMeshObject, TgxFaceGroup, TgxFGVertexIndexList,
- TFGVertexNormalTexIndexList, TgxAnimationControler, TgxFGIndexTexCoordList, TgxSkeletonCollider, TgxSkeletonColliderList]);
- finalization
- FreeAndNil(vVectorFileFormats);
- end.
|