| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388 |
- //
- // The graphics engine GXScene https://github.com/glscene
- //
- unit GXS.VectorFileObjects;
- (*
- Vector File related objects for GLScene
- The history is logged in a former GLS version of the unit.
- *)
- interface
- {$I GLScene.Defines.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.Math,
- System.SysUtils,
- System.Types,
- GXS.XOpenGL,
- GXS.BaseClasses,
- GXS.VectorLists,
- GXS.PersistentClasses,
- GLScene.VectorTypes,
- GLScene.VectorGeometry,
- GLScene.Strings,
- GLScene.Utils,
- GXS.GeometryBB,
- GXS.ApplicationFileIO,
- GXS.Scene,
- GXS.Texture,
- GXS.Material,
- GXS.Mesh,
- GXS.Octree,
- GXS.Silhouette,
- GXS.Context,
- GXS.Color,
- GXS.RenderContextInfo,
- GXS.Coordinates,
- GXS.TextureFormat,
- GXS.State,
- GXS.ImageUtils;
- 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: TQuaternionList;
- FLocalMatrixList: PMatrixArray;
- FTransformMode: TgxSkeletonFrameTransform;
- protected
- procedure SetPosition(const val: TgxAffineVectorList);
- procedure SetRotation(const val: TgxAffineVectorList);
- procedure SetQuaternion(const val: TQuaternionList);
- 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: TQuaternionList 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: TQuaternionList;
- 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. *)
- TfgxVertexIndexList = 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(TfgxVertexIndexList)
- 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. *)
- TFGIndexTexCoordList = class(TfgxVertexIndexList)
- 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 *)
- TMeshNormalsOrientation = (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: TMeshNormalsOrientation;
- protected
- procedure SetNormalsOrientation(const val: TMeshNormalsOrientation); virtual;
- public
- constructor Create(aOwner: TPersistent); override;
- function Owner: TgxBaseMesh;
- property NormalsOrientation: TMeshNormalsOrientation 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. *)
- TgxGLSMVectorFile = 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: TMeshNormalsOrientation;
- 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: TMeshNormalsOrientation);
- 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: TMeshNormalsOrientation 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 *)
- TActorFrameInterpolation = (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: TActorFrameInterpolation;
- 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: TActorFrameInterpolation 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;
- EInvalidVectorFile = 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.MeshUtils,
- 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 EInvalidVectorFile.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 := TQuaternionList.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: TQuaternionList);
- 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: TQuaternionList;
- 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 := TQuaternionList.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: TfgxVertexIndexList;
- 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 := TfgxVertexIndexList(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: TfgxVertexIndexList;
- 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 := TfgxVertexIndexList(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: TfgxVertexIndexList;
- 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 := TfgxVertexIndexList(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: TfgxVertexIndexList;
- 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 := TfgxVertexIndexList(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;
- // ------------------
- // ------------------ TfgxVertexIndexList ------------------
- // ------------------
- constructor TfgxVertexIndexList.Create;
- begin
- inherited;
- FVertexIndices := TgxIntegerList.Create;
- FMode := fgmmTriangles;
- end;
- destructor TfgxVertexIndexList.Destroy;
- begin
- FVertexIndices.Free;
- FIndexVBO.Free;
- inherited;
- end;
- procedure TfgxVertexIndexList.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 TfgxVertexIndexList.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 TfgxVertexIndexList.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 TfgxVertexIndexList.SetVertexIndices(const val: TgxIntegerList);
- begin
- FVertexIndices.Assign(val);
- InvalidateVBO;
- end;
- procedure TfgxVertexIndexList.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 TfgxVertexIndexList.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 TfgxVertexIndexList.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 TfgxVertexIndexList.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 TfgxVertexIndexList.Reverse;
- begin
- vertexIndices.Reverse;
- InvalidateVBO;
- end;
- procedure TfgxVertexIndexList.Add(idx: Integer);
- begin
- FVertexIndices.Add(idx);
- InvalidateVBO;
- end;
- procedure TfgxVertexIndexList.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 TfgxVertexIndexList.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 TfgxVertexIndexList.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 TfgxVertexIndexList.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;
- // ------------------
- // ------------------ TFGIndexTexCoordList ------------------
- // ------------------
- constructor TFGIndexTexCoordList.Create;
- begin
- inherited;
- FTexCoords := TgxAffineVectorList.Create;
- end;
- destructor TFGIndexTexCoordList.Destroy;
- begin
- FTexCoords.Free;
- inherited;
- end;
- procedure TFGIndexTexCoordList.WriteToFiler(writer: TgxVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- FTexCoords.WriteToFiler(writer);
- end;
- end;
- procedure TFGIndexTexCoordList.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 TFGIndexTexCoordList.SetTexCoords(const val: TgxAffineVectorList);
- begin
- FTexCoords.Assign(val);
- end;
- procedure TFGIndexTexCoordList.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 TFGIndexTexCoordList.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 TFGIndexTexCoordList.Add(idx: Integer; const texCoord: TAffineVector);
- begin
- texCoords.Add(texCoord);
- inherited Add(idx);
- end;
- procedure TFGIndexTexCoordList.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: TMeshNormalsOrientation);
- begin
- FNormalsOrientation := val;
- end;
- // ------------------
- // ------------------ TgxGLSMVectorFile ------------------
- // ------------------
- class function TgxGLSMVectorFile.Capabilities: TDataFileCapabilities;
- begin
- Result := [dfcRead, dfcWrite];
- end;
- procedure TgxGLSMVectorFile.LoadFromStream(aStream: TStream);
- begin
- Owner.MeshObjects.LoadFromStream(aStream);
- end;
- procedure TgxGLSMVectorFile.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: TMeshNormalsOrientation);
- 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 TfgxVertexIndexList 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(TfgxVertexIndexList) 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', TgxGLSMVectorFile);
- RegisterClasses([TgxFreeForm, TgxActor, TgxSkeleton, TgxSkeletonFrame, TgxSkeletonBone, TgxSkeletonMeshObject, TgxMeshObject,
- TgxSkeletonFrameList, TgxMeshMorphTarget, TgxMorphableMeshObject, TgxFaceGroup, TfgxVertexIndexList,
- TFGVertexNormalTexIndexList, TgxAnimationControler, TFGIndexTexCoordList, TgxSkeletonCollider, TgxSkeletonColliderList]);
- finalization
- FreeAndNil(vVectorFileFormats);
- end.
|