12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541 |
- //
- // The multimedia graphics platform GLScene https://github.com/glscene
- //
- unit GLS.VectorFileObjects;
- (* Vector File related objects *)
- interface
- {$I GLScene.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.SysUtils,
- System.Types,
- System.Math,
- VCL.Consts,
- GLS.OpenGLTokens,
- GLS.Scene,
- GLS.VectorGeometry,
- GLS.VectorTypes,
- GLS.VectorTypesExt,
- GLS.VectorLists,
- GLS.PersistentClasses,
- GLS.Silhouette,
- GLS.Strings,
- GLS.Texture,
- GLS.Material,
- GLS.Mesh,
- GLS.Logger,
- GLS.Octree,
- GLS.GeometryBB,
- GLS.ApplicationFileIO,
- GLS.Context,
- GLS.Color,
- GLS.PipelineTransformation,
- GLS.Selection,
- GLS.RenderContextInfo,
- GLS.Coordinates,
- GLS.BaseClasses,
- GLS.TextureFormat;
- type
- TGLMeshObjectList = class;
- TGLFaceGroups = class;
- TGLMeshAutoCentering = (macCenterX, macCenterY, macCenterZ, macUseBarycenter, macRestorePosition);
- TGLMeshAutoCenterings = set of TGLMeshAutoCentering;
- TGLMeshObjectMode = (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
- *)
- TGLBaseMeshObject = class(TGLPersistentObject)
- private
- FName: string;
- FVertices: TGLAffineVectorList;
- FNormals: TGLAffineVectorList;
- FVisible: Boolean;
- protected
- procedure SetVertices(const val: TGLAffineVectorList); inline;
- procedure SetNormals(const val: TGLAffineVectorList); inline;
- procedure ContributeToBarycenter(var currentSum: TAffineVector; var nb: Integer); virtual;
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); 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: TGLIntegerList; mode: TGLMeshObjectMode;
- NormalIndices: TGLIntegerList = nil);
- // Builds normals faster without index calculations for the stripe mode
- procedure GenericOrderedBuildNormals (mode: TGLMeshObjectMode);
- (*
- 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: TGLAffineVectorList = nil;
- Normals: TGLAffineVectorList = nil): TGLAffineVectorList; virtual;
- property Name: string read FName write FName;
- property Visible: Boolean read FVisible write FVisible;
- property Vertices: TGLAffineVectorList read FVertices write SetVertices;
- property Normals: TGLAffineVectorList read FNormals write SetNormals;
- end;
- TGLSkeletonFrameList = class;
- TGLSkeletonFrameTransform = (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)
- *)
- TGLSkeletonFrame = class(TGLPersistentObject)
- private
- FOwner: TGLSkeletonFrameList;
- FName: string;
- FPosition: TGLAffineVectorList;
- FRotation: TGLAffineVectorList;
- FQuaternion: TGLQuaternionList;
- FLocalMatrixList: PMatrixArray;
- FTransformMode: TGLSkeletonFrameTransform;
- protected
- procedure SetPosition(const val: TGLAffineVectorList);
- procedure SetRotation(const val: TGLAffineVectorList);
- procedure SetQuaternion(const val: TGLQuaternionList);
- public
- constructor CreateOwned(aOwner: TGLSkeletonFrameList);
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- property Owner: TGLSkeletonFrameList read FOwner;
- property Name: string read FName write FName;
- // Position values for the joints.
- property Position: TGLAffineVectorList read FPosition write SetPosition;
- // Rotation values for the joints.
- property Rotation: TGLAffineVectorList read FRotation write SetRotation;
- (* Quaternions are an alternative to Euler rotations to build the
- global matrices for the skeleton bones. *)
- property Quaternion: TGLQuaternionList read FQuaternion write SetQuaternion;
- (* TransformMode indicates whether to use Rotation or Quaternion to build
- the local transform matrices. *)
- property TransformMode: TGLSkeletonFrameTransform 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 TGLSkeletonFrame objects
- TGLSkeletonFrameList = class(TGLPersistentObjectList)
- private
- FOwner: TPersistent;
- protected
- function GetSkeletonFrame(Index: Integer): TGLSkeletonFrame;
- public
- constructor CreateOwned(aOwner: TPersistent);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TGLVirtualReader); 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]: TGLSkeletonFrame read GetSkeletonFrame; default;
- end;
- TGLSkeleton = class;
- TGLSkeletonBone = class;
- // A list of skeleton bones
- TGLSkeletonBoneList = class(TGLPersistentObjectList)
- private
- FSkeleton: TGLSkeleton; // not persistent
- protected
- FGlobalMatrix: TGLMatrix;
- function GetSkeletonBone(Index: Integer): TGLSkeletonBone;
- procedure AfterObjectCreatedByReader(Sender: TObject); override;
- public
- constructor CreateOwned(aOwner: TGLSkeleton);
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- property Skeleton: TGLSkeleton read FSkeleton;
- property Items[Index: Integer]: TGLSkeletonBone read GetSkeletonBone; default;
- // Returns a bone by its BoneID, nil if not found.
- function BoneByID(anID: Integer): TGLSkeletonBone; virtual;
- // Returns a bone by its Name, nil if not found.
- function BoneByName(const aName: string): TGLSkeletonBone; virtual;
- // Number of bones (including all children and self).
- function BoneCount: Integer;
- // Render skeleton wireframe
- procedure BuildList(var mrci: TGLRenderContextInfo); virtual; abstract;
- procedure PrepareGlobalMatrices; virtual;
- end;
- // This list store skeleton root bones exclusively
- TGLSkeletonRootBoneList = class(TGLSkeletonBoneList)
- public
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- // Render skeleton wireframe
- procedure BuildList(var mrci: TGLRenderContextInfo); override;
- property GlobalMatrix: TGLMatrix 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 TGLSkeletonFrame, but the calculated bone
- matrices are stored here.
- *)
- TGLSkeletonBone = class(TGLSkeletonBoneList)
- private
- FOwner: TGLSkeletonBoneList; // indirectly persistent
- FBoneID: Integer;
- FName: string;
- FColor: Cardinal;
- protected
- function GetSkeletonBone(Index: Integer): TGLSkeletonBone;
- procedure SetColor(const val: Cardinal);
- public
- constructor CreateOwned(aOwner: TGLSkeletonBoneList);
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- // Render skeleton wireframe
- procedure BuildList(var mrci: TGLRenderContextInfo); override;
- property Owner: TGLSkeletonBoneList 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]: TGLSkeletonBone read GetSkeletonBone; default;
- // Returns a bone by its BoneID, nil if not found.
- function BoneByID(anID: Integer): TGLSkeletonBone; override;
- function BoneByName(const aName: string): TGLSkeletonBone; override;
- // Set the bone's matrix. Becareful using this.
- procedure SetGlobalMatrix(const Matrix: TGLMatrix); // Ragdoll
- // Set the bone's GlobalMatrix. Used for Ragdoll.
- procedure SetGlobalMatrixForRagDoll(const RagDollMatrix: TGLMatrix); // 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: TGLMatrix read FGlobalMatrix;
- // Free all sub bones and reset BoneID and Name.
- procedure Clean; override;
- end;
- TGLSkeletonColliderList = 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.
- *)
- TGLSkeletonCollider = class(TGLPersistentObject)
- private
- FOwner: TGLSkeletonColliderList;
- FBone: TGLSkeletonBone;
- FBoneID: Integer;
- FLocalMatrix, FGlobalMatrix: TGLMatrix;
- FAutoUpdate: Boolean;
- protected
- procedure SetBone(const val: TGLSkeletonBone);
- procedure SetLocalMatrix(const val: TGLMatrix);
- public
- constructor Create; override;
- constructor CreateOwned(AOwner: TGLSkeletonColliderList);
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); 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: TGLSkeletonColliderList read FOwner;
- // The bone that this collider associates with.
- property Bone: TGLSkeletonBone read FBone write SetBone;
- // Offset and orientation of the collider in the associated bone's space.
- property LocalMatrix: TGLMatrix read FLocalMatrix write SetLocalMatrix;
- (* Global offset and orientation of the collider.
- This gets set in the AlignCollider method. *)
- property GlobalMatrix: TGLMatrix read FGlobalMatrix;
- property AutoUpdate: Boolean read FAutoUpdate write FAutoUpdate;
- end;
- // List class for storing TGLSkeletonCollider objects
- TGLSkeletonColliderList = class(TGLPersistentObjectList)
- private
- FOwner: TPersistent;
- protected
- function GetSkeletonCollider(Index: Integer): TGLSkeletonCollider;
- public
- constructor CreateOwned(AOwner: TPersistent);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure Clear; override;
- // Calls AlignCollider for each collider in the list.
- procedure AlignColliders;
- property Owner: TPersistent read FOwner;
- property Items[Index: Integer]: TGLSkeletonCollider read GetSkeletonCollider; default;
- end;
- TGLBaseMesh = class;
- // Small structure to store a weighted lerp for use in blending
- TGLBlendedLerpInfo = record
- FrameIndex1, frameIndex2: Integer;
- LerpFactor: Single;
- Weight: Single;
- ExternalPositions: TGLAffineVectorList;
- ExternalRotations: TGLAffineVectorList;
- ExternalQuaternions: TGLQuaternionList;
- 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. *)
- TGLSkeleton = class(TGLPersistentObject)
- private
- FOwner: TGLBaseMesh;
- FRootBones: TGLSkeletonRootBoneList;
- FFrames: TGLSkeletonFrameList;
- FCurrentFrame: TGLSkeletonFrame; // not persistent
- FBonesByIDCache: TList;
- FColliders: TGLSkeletonColliderList;
- FRagDollEnabled: Boolean; // ragdoll
- FMorphInvisibleParts: Boolean;
- protected
- procedure SetRootBones(const val: TGLSkeletonRootBoneList);
- procedure SetFrames(const val: TGLSkeletonFrameList);
- function GetCurrentFrame: TGLSkeletonFrame;
- procedure SetCurrentFrame(val: TGLSkeletonFrame);
- procedure SetColliders(const val: TGLSkeletonColliderList);
- public
- constructor CreateOwned(aOwner: TGLBaseMesh);
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- property Owner: TGLBaseMesh read FOwner;
- property RootBones: TGLSkeletonRootBoneList read FRootBones write SetRootBones;
- property Frames: TGLSkeletonFrameList read FFrames write SetFrames;
- property CurrentFrame: TGLSkeletonFrame read GetCurrentFrame write SetCurrentFrame;
- property Colliders: TGLSkeletonColliderList read FColliders write SetColliders;
- procedure FlushBoneByIDCache;
- function BoneByID(anID: Integer): TGLSkeletonBone;
- function BoneByName(const aName: string): TGLSkeletonBone;
- function BoneCount: Integer;
- procedure MorphTo(frameIndex: Integer); overload;
- procedure MorphTo(frame: TGLSkeletonFrame); overload;
- procedure Lerp(frameIndex1, frameIndex2: Integer; lerpFactor: Single);
- procedure BlendedLerps(const lerpInfos: array of TGLBlendedLerpInfo);
- (*
- 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: TGLSkeleton);
- // Release bones and frames info.
- procedure Clear;
- // Backup and prepare the BoneMatrixInvertedMeshes to use with ragdolls
- procedure StartRagdoll;
- // Restore the BoneMatrixInvertedMeshes to stop the ragdoll
- procedure StopRagdoll;
- (*
- Turning this option off (by default) allows 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 TGLMeshObject.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
- *)
- TGLMeshObjectRenderingOption = (moroGroupByMaterial);
- TGLMeshObjectRenderingOptions = set of TGLMeshObjectRenderingOption;
- TGLVBOBuffer = (vbVertices, vbNormals, vbColors, vbTexCoords, vbLightMapTexCoords, vbTexCoordsEx);
- TGLVBOBuffers = set of TGLVBOBuffer;
- (*
- Base mesh class. Introduces base methods and properties for mesh objects.
- Subclasses are named "TGLMOxxx".
- *)
- TGLMeshObject = class(TGLBaseMeshObject)
- private
- FOwner: TGLMeshObjectList;
- FExtentCacheRevision: Cardinal;
- FTexCoords: TGLAffineVectorList; // provision for 3D textures
- FLightMapTexCoords: TGLAffineVectorList; // reserved for 2D surface needs
- FColors: TGLVectorList;
- FFaceGroups: TGLFaceGroups;
- FMode: TGLMeshObjectMode;
- FRenderingOptions: TGLMeshObjectRenderingOptions;
- FArraysDeclared: Boolean; // not persistent
- FLightMapArrayEnabled: Boolean; // not persistent
- FLastLightMapIndex: Integer; // not persistent
- FTexCoordsEx: TList;
- FBinormalsTexCoordIndex: Integer;
- FTangentsTexCoordIndex: Integer;
- FLastXOpenGLTexMapping: Cardinal;
- FUseVBO: Boolean;
- FVerticesVBO: TGLVBOHandle;
- FNormalsVBO: TGLVBOHandle;
- FColorsVBO: TGLVBOHandle;
- FTexCoordsVBO: array of TGLVBOHandle;
- FLightmapTexCoordsVBO: TGLVBOHandle;
- FValidBuffers: TGLVBOBuffers;
- FExtentCache: TAABB;
- procedure SetUseVBO(const Value: Boolean);
- procedure SetValidBuffers(Value: TGLVBOBuffers);
- protected
- procedure SetTexCoords(const val: TGLAffineVectorList);
- procedure SetLightmapTexCoords(const val: TGLAffineVectorList);
- procedure SetColors(const val: TGLVectorList);
- procedure BufferArrays;
- procedure DeclareArraysToOpenGL(var mrci: TGLRenderContextInfo;
- EvenIfAlreadyDeclared: Boolean = False);
- procedure DisableOpenGLArrays(var mrci: TGLRenderContextInfo);
- procedure EnableLightMapArray(var mrci: TGLRenderContextInfo);
- procedure DisableLightMapArray(var mrci: TGLRenderContextInfo);
- procedure SetTexCoordsEx(Index: Integer; const val: TGLVectorList);
- function GetTexCoordsEx(Index: Integer): TGLVectorList;
- procedure SetBinormals(const val: TGLVectorList);
- function GetBinormals: TGLVectorList;
- procedure SetBinormalsTexCoordIndex(const val: Integer);
- procedure SetTangents(const val: TGLVectorList);
- function GetTangents: TGLVectorList;
- procedure SetTangentsTexCoordIndex(const val: Integer);
- property ValidBuffers: TGLVBOBuffers read FValidBuffers write SetValidBuffers;
- public
- // Creates, assigns Owner and adds to list.
- constructor CreateOwned(AOwner: TGLMeshObjectList);
- constructor Create; override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure Clear; override;
- function ExtractTriangles(texCoords: TGLAffineVectorList = nil;
- Normals: TGLAffineVectorList = nil): TGLAffineVectorList; override;
- // Returns number of triangles in the mesh object.
- function TriangleCount: Integer; virtual;
- procedure PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
- 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: TGLRenderContextInfo); virtual;
- // Similar to regular scene object's BuildList method
- procedure BuildList(var mrci: TGLRenderContextInfo); 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: TGLVector;
- // 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: TGLAffineVectorList; var v0, v1, v2: TAffineVector); overload;
- procedure GetTriangleData(tri: Integer; list: TGLVectorList; var v0, v1, v2: TGLVector); overload;
- // Sets the triangle data of a given triangle
- procedure SetTriangleData(tri: Integer; list: TGLAffineVectorList; const v0, v1, v2: TAffineVector); overload;
- procedure SetTriangleData(tri: Integer; list: TGLVectorList; const v0, v1, v2: TGLVector); 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: TGLMeshObjectList read FOwner;
- property Mode: TGLMeshObjectMode read FMode write FMode;
- property TexCoords: TGLAffineVectorList read FTexCoords write SetTexCoords;
- property LightMapTexCoords: TGLAffineVectorList read FLightMapTexCoords write SetLightmapTexCoords;
- property Colors: TGLVectorList read FColors write SetColors;
- property FaceGroups: TGLFaceGroups read FFaceGroups;
- property RenderingOptions: TGLMeshObjectRenderingOptions 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]: TGLVectorList read GetTexCoordsEx write SetTexCoordsEx;
- // A TexCoordsEx list wrapper for binormals usage, returns TexCoordsEx[BinormalsTexCoordIndex].
- property Binormals: TGLVectorList read GetBinormals write SetBinormals;
- // A TexCoordsEx list wrapper for tangents usage, returns TexCoordsEx[BinormalsTexCoordIndex].
- property Tangents: TGLVectorList 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 TGLMeshObject objects.
- TGLMeshObjectList = class(TGLPersistentObjectList)
- private
- FOwner: TGLBaseMesh;
- // Returns True if all its MeshObjects use VBOs.
- function GetUseVBO: Boolean;
- procedure SetUseVBO(const Value: Boolean);
- protected
- function GetMeshObject(Index: Integer): TGLMeshObject; inline;
- public
- constructor CreateOwned(aOwner: TGLBaseMesh);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
- 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: TGLRenderContextInfo); virtual;
- // Similar to regular scene object's BuildList method
- procedure BuildList(var mrci: TGLRenderContextInfo); 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: TGLAffineVectorList = nil; normals: TGLAffineVectorList = nil): TGLAffineVectorList;
- // Returns number of triangles in the meshes of the list.
- function TriangleCount: Integer;
- // Returns the total Area of meshes in the list.
- function Area: Single;
- // Returns the total volume of meshes in the list.
- function Volume: Single;
- (* 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(const MeshName: string): TGLMeshObject;
- property Owner: TGLBaseMesh read FOwner;
- procedure Clear; override;
- property Items[Index: Integer]: TGLMeshObject read GetMeshObject; default;
- end;
- TGLMeshObjectListClass = class of TGLMeshObjectList;
- TGLMeshMorphTargetList = class;
- // A morph target, stores alternate lists of vertices and normals.
- TGLMeshMorphTarget = class(TGLBaseMeshObject)
- private
- FOwner: TGLMeshMorphTargetList;
- public
- constructor CreateOwned(aOwner: TGLMeshMorphTargetList);
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- property Owner: TGLMeshMorphTargetList read FOwner;
- end;
- // A list of TGLMeshMorphTarget objects.
- TGLMeshMorphTargetList = class(TGLPersistentObjectList)
- private
- FOwner: TPersistent;
- protected
- function GeTGLMeshMorphTarget(Index: Integer): TGLMeshMorphTarget;
- public
- constructor CreateOwned(AOwner: TPersistent);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure Translate(const delta: TAffineVector);
- property Owner: TPersistent read FOwner;
- procedure Clear; override;
- property Items[Index: Integer]: TGLMeshMorphTarget read GeTGLMeshMorphTarget; default;
- end;
- (* Mesh object with support for morph targets. The morph targets allow to change
- vertices and normals according to pre-existing "morph targets". *)
- TGLMorphableMeshObject = class(TGLMeshObject)
- private
- FMorphTargets: TGLMeshMorphTargetList;
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); 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: TGLMeshMorphTargetList read FMorphTargets;
- end;
- TGLVertexBoneWeight = packed record
- BoneID: Integer;
- weight: Single;
- end;
- TGLVertexBoneWeightArray = array [0 .. MaxInt div (2 * SizeOf(TGLVertexBoneWeight))] of TGLVertexBoneWeight;
- PGLVertexBoneWeightArray = ^TGLVertexBoneWeightArray;
- TGLVerticesBoneWeights = array [0 .. MaxInt div (2 * SizeOf(PGLVertexBoneWeightArray))] of PGLVertexBoneWeightArray;
- PGLVerticesBoneWeights = ^TGLVerticesBoneWeights;
- TGLVertexBoneWeightDynArray = array of TGLVertexBoneWeight;
- (* A mesh object with vertice bone attachments.
- The class adds per vertex bone weights to the standard morphable mesh.
- The TGLVertexBoneWeight 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). *)
- TGLSkeletonMeshObject = class(TGLMorphableMeshObject)
- private
- FVerticesBonesWeights: PGLVerticesBoneWeights;
- 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: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure Clear; override;
- property VerticesBonesWeights: PGLVerticesBoneWeights 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: TGLVertexBoneWeightDynArray; const vertex, normal: TAffineVector): Integer; overload;
- procedure AddWeightedBone(aBoneID: Integer; aWeight: Single);
- procedure AddWeightedBones(const boneIDs: TGLVertexBoneWeightDynArray);
- procedure PrepareBoneMatrixInvertedMeshes;
- procedure ApplyCurrentSkeletonFrame(normalize: Boolean);
- end;
- (* Describes a face group of a TGLMeshObject.
- 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. *)
- TGLFaceGroup = class(TGLPersistentObject)
- private
- FOwner: TGLFaceGroups;
- FMaterialName: string;
- FMaterialCache: TGLLibMaterial;
- FLightMapIndex: Integer;
- FRenderGroupID: Integer;
- // NOT Persistent, internal use only (rendering options)
- protected
- procedure AttachLightmap(lightMap: TGLTexture; var mrci: TGLRenderContextInfo);
- procedure AttachOrDetachLightmap(var mrci: TGLRenderContextInfo);
- public
- constructor CreateOwned(aOwner: TGLFaceGroups); virtual;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
- procedure DropMaterialLibraryCache;
- procedure BuildList(var mrci: TGLRenderContextInfo); virtual; abstract;
- (* Add to the list the triangles corresponding to the facegroup.
- This function is used by TGLMeshObjects ExtractTriangles to retrieve
- all the triangles in a mesh. *)
- procedure AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
- aNormals: TGLAffineVectorList = 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: TGLFaceGroups read FOwner write FOwner;
- property MaterialName: string read FMaterialName write FMaterialName;
- property MaterialCache: TGLLibMaterial 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. *)
- TGLFaceGroupMeshMode = (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. *)
- TFGVertexIndexList = class(TGLFaceGroup)
- private
- FVertexIndices: TGLIntegerList;
- FIndexVBO: TGLVBOElementArrayHandle;
- FMode: TGLFaceGroupMeshMode;
- procedure SetupVBO;
- procedure InvalidateVBO;
- protected
- procedure SetVertexIndices(const val: TGLIntegerList);
- procedure AddToList(Source, destination: TGLAffineVectorList; indices: TGLIntegerList);
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure BuildList(var mrci: TGLRenderContextInfo); override;
- procedure AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
- aNormals: TGLAffineVectorList = nil); override;
- function TriangleCount: Integer; override;
- procedure Reverse; override;
- procedure Add(idx: Integer); inline;
- 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: TGLFaceGroupMeshMode read FMode write FMode;
- property VertexIndices: TGLIntegerList 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(TFGVertexIndexList)
- private
- FNormalIndices: TGLIntegerList;
- FTexCoordIndices: TGLIntegerList;
- protected
- procedure SetNormalIndices(const val: TGLIntegerList); inline;
- procedure SetTexCoordIndices(const val: TGLIntegerList); inline;
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure BuildList(var mrci: TGLRenderContextInfo); override;
- procedure AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
- aNormals: TGLAffineVectorList = nil); override;
- procedure Add(vertexIdx, normalIdx, texCoordIdx: Integer);
- property NormalIndices: TGLIntegerList read FNormalIndices write SetNormalIndices;
- property TexCoordIndices: TGLIntegerList 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(TFGVertexIndexList)
- private
- FTexCoords: TGLAffineVectorList;
- protected
- procedure SetTexCoords(const val: TGLAffineVectorList);
- public
- constructor Create; override;
- destructor Destroy; override;
- procedure WriteToFiler(writer: TGLVirtualWriter); override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure BuildList(var mrci: TGLRenderContextInfo); override;
- procedure AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
- aNormals: TGLAffineVectorList = nil); override;
- procedure Add(idx: Integer; const texCoord: TAffineVector); overload;
- procedure Add(idx: Integer; const s, t: Single); overload;
- property TexCoords: TGLAffineVectorList read FTexCoords write SetTexCoords;
- end;
- // A list of TGLFaceGroup objects.
- TGLFaceGroups = class(TGLPersistentObjectList)
- private
- FOwner: TGLMeshObject;
- protected
- function GetFaceGroup(Index: Integer): TGLFaceGroup;
- public
- constructor CreateOwned(aOwner: TGLMeshObject);
- destructor Destroy; override;
- procedure ReadFromFiler(reader: TGLVirtualReader); override;
- procedure PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
- procedure DropMaterialLibraryCache;
- property Owner: TGLMeshObject read FOwner;
- procedure Clear; override;
- property Items[Index: Integer]: TGLFaceGroup read GetFaceGroup; default;
- procedure AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil; aNormals: TGLAffineVectorList = nil);
- // Material Library of the owner TGLBaseMesh.
- function MaterialLibrary: TGLMaterialLibrary;
- // 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 *)
- TGLMeshNormalsOrientation = (mnoDefault, mnoInvert); // , mnoAutoSolid, mnoAutoHollow);
- (* Abstract base class for different vector file formats.
- The actual implementation for these files (3DS, DXF..) must be done
- separately. The concept for TGLVectorFile is very similar to TGraphic *)
- TGLVectorFile = class(TGLDataFile)
- private
- FNormalsOrientation: TGLMeshNormalsOrientation;
- protected
- procedure SetNormalsOrientation(const val: TGLMeshNormalsOrientation); virtual;
- public
- constructor Create(AOwner: TPersistent); override;
- function Owner: TGLBaseMesh;
- property NormalsOrientation: TGLMeshNormalsOrientation read FNormalsOrientation write SetNormalsOrientation;
- end;
- TGLVectorFileClass = class of TGLVectorFile;
- (* GLSM (GLScene Mesh) vector file.
- This corresponds to the 'native' GLScene format, and object persistence
- stream, which should be the 'fastest' of all formats to load, and supports
- all of GLScene features. *)
- TGLSMVectorFile = class(TGLVectorFile)
- public
- class function Capabilities: TGLDataFileCapabilities; override;
- procedure LoadFromStream(aStream: TStream); override;
- procedure SaveToStream(aStream: TStream); override;
- end;
- // Base class for mesh objects.
- TGLBaseMesh = class(TGLSceneObject)
- private
- FNormalsOrientation: TGLMeshNormalsOrientation;
- FMaterialLibrary: TGLMaterialLibrary;
- FLightmapLibrary: TGLMaterialLibrary;
- FAxisAlignedDimensionsCache: TGLVector;
- FBaryCenterOffsetChanged: Boolean;
- FBaryCenterOffset: TGLVector;
- FUseMeshMaterials: Boolean;
- FOverlaySkeleton: Boolean;
- FIgnoreMissingTextures: Boolean;
- FAutoCentering: TGLMeshAutoCenterings;
- FAutoScaling: TGLCoordinates;
- FMaterialLibraryCachesPrepared: Boolean;
- FConnectivity: TObject;
- FLastLoadedFilename: string;
- protected
- FMeshObjects: TGLMeshObjectList; // < a list of mesh objects
- FSkeleton: TGLSkeleton; // < skeleton data & frames
- procedure SetUseMeshMaterials(const val: Boolean);
- procedure SetMaterialLibrary(const val: TGLMaterialLibrary);
- procedure SetLightmapLibrary(const val: TGLMaterialLibrary);
- procedure SetNormalsOrientation(const val: TGLMeshNormalsOrientation);
- procedure SetOverlaySkeleton(const val: Boolean);
- procedure SetAutoScaling(const Value: TGLCoordinates);
- procedure DestroyHandle; override;
- (* Invoked after creating a TGLVectorFile and before loading.
- Triggered by LoadFromFile/Stream and AddDataFromFile/Stream.
- Allows to adjust/transfer subclass-specific features. *)
- procedure PrepareVectorFile(aFile: TGLVectorFile); 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: TGLRenderContextInfo); virtual;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- function AxisAlignedDimensionsUnscaled: TGLVector; override;
- function BarycenterOffset: TGLVector;
- function BarycenterPosition: TGLVector;
- function BarycenterAbsolutePosition: TGLVector; override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- procedure DoRender(var rci: TGLRenderContextInfo; 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: TGLVector; intersectPoint: PGLVector = nil;
- intersectNormal: PGLVector = nil): Boolean; override;
- function GenerateSilhouette(const silhouetteParameters: TGLSilhouetteParameters): TGLSilhouette; 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: TGLMeshObjectList read FMeshObjects;
- property Skeleton: TGLSkeleton 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 to
- by GLScene. *)
- 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 to
- by GLScene. *)
- 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 TMeshObjects). *)
- property AutoCentering: TGLMeshAutoCenterings 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 TMeshObjects). *)
- property AutoScaling: TGLCoordinates 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: TGLMaterialLibrary 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: TGLMaterialLibrary 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: TGLMeshNormalsOrientation 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. *)
- TGLFreeForm = class(TGLBaseMesh)
- private
- FOctree: TGLOctree;
- public
- constructor Create(aOwner: TComponent); override;
- destructor Destroy; override;
- function OctreeRayCastIntersect(const rayStart, rayVector: TGLVector; intersectPoint: PGLVector = nil;
- intersectNormal: PGLVector = nil): Boolean;
- function OctreeSphereSweepIntersect(const rayStart, rayVector: TGLVector; const velocity, radius: Single;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = 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: TGLVector): Boolean;
- function OctreeAABBIntersect(const AABB: TAABB; objMatrix, invObjMatrix: TGLMatrix;
- triangles: TGLAffineVectorList = nil): Boolean;
- // TODO: function OctreeSphereIntersect
- // Octree support *experimental*. Use only if you understand what you're doing!
- property Octree: TGLOctree read FOctree;
- 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. *)
- TGLActorOption = (aoSkeletonNormalizeNormals);
- TGLActorOptions = set of TGLActorOption;
- const
- cDefaultActorOptions = [aoSkeletonNormalizeNormals];
- type
- TGLActor = class;
- TGLActorAnimationReference = (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 TGLAnimationControler. *)
- TGLActorAnimation = class(TCollectionItem)
- private
- FName: string;
- FStartFrame: Integer;
- FEndFrame: Integer;
- FReference: TGLActorAnimationReference;
- protected
- function GetDisplayName: string; override;
- function FrameCount: Integer;
- procedure SetStartFrame(const val: Integer);
- procedure SetEndFrame(const val: Integer);
- procedure SetReference(val: TGLActorAnimationReference);
- 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: TGLActor;
- (* 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: TGLActorAnimationReference read FReference write
- SetReference default aarMorph;
- end;
- TGLActorAnimationName = string;
- // Collection of actor animations sequences.
- TGLActorAnimations = class(TCollection)
- private
- FOwner: TGLActor;
- protected
- function GetOwner: TPersistent; override;
- procedure SetItems(Index: Integer; const val: TGLActorAnimation);
- function GetItems(Index: Integer): TGLActorAnimation;
- public
- constructor Create(AOwner: TGLActor);
- function Add: TGLActorAnimation;
- function FindItemID(ID: Integer): TGLActorAnimation;
- function FindName(const aName: string): TGLActorAnimation;
- function FindFrame(aFrame: Integer; aReference: TGLActorAnimationReference): TGLActorAnimation;
- 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]: TGLActorAnimation read GetItems write
- SetItems; default;
- function Last: TGLActorAnimation;
- end;
- // Base class for skeletal animation control.
- TGLBaseAnimationControler = class(TComponent)
- private
- FEnabled: Boolean;
- FActor: TGLActor;
- protected
- procedure Notification(AComponent: TComponent; Operation: TOperation); override;
- procedure SetEnabled(const val: Boolean);
- procedure SetActor(const val: TGLActor);
- procedure DoChange; virtual;
- function Apply(var lerpInfo: TGLBlendedLerpInfo): Boolean; virtual;
- public
- constructor Create(AOwner: TComponent); override;
- destructor Destroy; override;
- published
- property Enabled: Boolean read FEnabled write SetEnabled default True;
- property Actor: TGLActor 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 TGLActor), 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. *)
- TGLAnimationControler = class(TGLBaseAnimationControler)
- private
- FAnimationName: TGLActorAnimationName;
- FRatio: Single;
- protected
- procedure SetAnimationName(const val: TGLActorAnimationName);
- procedure SetRatio(const val: Single);
- procedure DoChange; override;
- function Apply(var lerpInfo: TGLBlendedLerpInfo): 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 *)
- TGLActorFrameInterpolation = (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 *)
- TGLActorAnimationMode = (aamNone, aamPlayOnce, aamLoop, aamBounceForward,
- aamBounceBackward, aamLoopBackward, aamExternal);
- (* Mesh class specialized in animated meshes.
- The TGLActor provides a quick interface to animated meshes based on morph
- or skeleton frames, it is capable of performing frame interpolation and
- animation blending (via TGLAnimationController components). *)
- TGLActor = class(TGLBaseMesh)
- private
- FStartFrame, FEndFrame: Integer;
- FReference: TGLActorAnimationReference;
- FCurrentFrame: Integer;
- FCurrentFrameDelta: Single;
- FFrameInterpolation: TGLActorFrameInterpolation;
- FInterval: Integer;
- FAnimationMode: TGLActorAnimationMode;
- FOnFrameChanged: TNotifyEvent;
- FOnEndFrameReached, FOnStartFrameReached: TNotifyEvent;
- FAnimations: TGLActorAnimations;
- FTargetSmoothAnimation: TGLActorAnimation;
- FControlers: TList;
- FOptions: TGLActorOptions;
- protected
- procedure SetCurrentFrame(val: Integer);
- procedure SetStartFrame(val: Integer);
- procedure SetEndFrame(val: Integer);
- procedure SetReference(val: TGLActorAnimationReference);
- procedure SetAnimations(const val: TGLActorAnimations);
- function StoreAnimations: Boolean;
- procedure SetOptions(const val: TGLActorOptions);
- procedure PrepareMesh; override;
- procedure PrepareBuildList(var mrci: TGLRenderContextInfo); override;
- procedure DoAnimate; virtual;
- procedure RegisterControler(aControler: TGLBaseAnimationControler);
- procedure UnRegisterControler(aControler: TGLBaseAnimationControler);
- public
- constructor Create(aOwner: TComponent); override;
- destructor Destroy; override;
- procedure Assign(Source: TPersistent); override;
- procedure BuildList(var rci: TGLRenderContextInfo); override;
- procedure DoProgress(const progressTime: TGLProgressTimes); override;
- procedure LoadFromStream(const filename: string; aStream: TStream); override;
- procedure SwitchToAnimation(anAnimation: TGLActorAnimation; 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: TGLActor);
- // Provides a direct access to FCurrentFrame without any checks. Used in TGLActorProxy
- 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: TGLActorAnimationReference 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: TGLActorFrameInterpolation read FFrameInterpolation
- write FFrameInterpolation default afpLinear;
- // See TGLActorAnimationMode.
- property AnimationMode: TGLActorAnimationMode 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: TGLActorOptions 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: TGLActorAnimations read FAnimations write SetAnimations stored StoreAnimations;
- property AutoCentering;
- property MaterialLibrary;
- property LightmapLibrary;
- property UseMeshMaterials;
- property NormalsOrientation;
- property OverlaySkeleton;
- end;
- TGLVectorFileFormat = class
- public
- VectorFileClass: TGLVectorFileClass;
- Extension: string;
- Description: string;
- DescResID: Integer;
- end;
- // Stores registered vector file formats
- TGLVectorFileFormatsList = class(TGLPersistentObjectList)
- public
- destructor Destroy; override;
- procedure Add(const Ext, Desc: string; DescID: Integer; AClass: TGLVectorFileClass);
- function FindExt(Ext: string): TGLVectorFileClass;
- function FindFromFileName(const filename: string): TGLVectorFileClass;
- procedure Remove(AClass: TGLVectorFileClass);
- procedure BuildFilterStrings(vectorFileClass: TGLVectorFileClass;
- 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: TGLVectorFileFormatsList;
- // 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: TGLVectorFileClass);
- procedure UnregisterVectorFileClass(AClass: TGLVectorFileClass);
- var
- vGLVectorFileObjectsAllocateMaterials: Boolean = True;
- // Flag to avoid loading materials (useful for IDE Extentions or scene editors)
- vGLVectorFileObjectsEnableVBOByDefault: Boolean = True;
- // ------------------------------------------------------------------
- implementation
- // ------------------------------------------------------------------
- uses
- GLS.XOpenGL,
- GLS.MeshUtils,
- GLS.State,
- GLS.Utils,
- GLS.BaseMeshSilhouette;
- var
- vVectorFileFormats: TGLVectorFileFormatsList;
- vNextRenderGroupID: Integer = 1;
- const
- cAAFHeader: AnsiString = 'AAF';
- function GetVectorFileFormats: TGLVectorFileFormatsList;
- begin
- if not Assigned(vVectorFileFormats) then
- vVectorFileFormats := TGLVectorFileFormatsList.Create;
- Result := vVectorFileFormats;
- end;
- function VectorFileFormatsFilter: string;
- var
- f: string;
- begin
- GetVectorFileFormats.BuildFilterStrings(TGLVectorFile, Result, f);
- end;
- function VectorFileFormatsSaveFilter: string;
- var
- f: string;
- begin
- GetVectorFileFormats.BuildFilterStrings(TGLVectorFile, Result, f, False, True);
- end;
- procedure RegisterVectorFileFormat(const aExtension, aDescription: string; AClass: TGLVectorFileClass);
- begin
- RegisterClass(AClass);
- GetVectorFileFormats.Add(aExtension, aDescription, 0, AClass);
- end;
- procedure UnregisterVectorFileClass(AClass: TGLVectorFileClass);
- begin
- if Assigned(vVectorFileFormats) then
- vVectorFileFormats.Remove(AClass);
- end;
- function VectorFileFormatExtensionByIndex(Index: Integer): string;
- begin
- Result := GetVectorFileFormats.FindExtByIndex(index);
- end;
- // ------------------
- // ------------------ TGLVectorFileFormatsList ------------------
- // ------------------
- destructor TGLVectorFileFormatsList.Destroy;
- begin
- Clean;
- inherited;
- end;
- procedure TGLVectorFileFormatsList.Add(const Ext, Desc: string; DescID: Integer; AClass: TGLVectorFileClass);
- var
- newRec: TGLVectorFileFormat;
- begin
- newRec := TGLVectorFileFormat.Create;
- with newRec do
- begin
- Extension := AnsiLowerCase(Ext);
- VectorFileClass := AClass;
- Description := Desc;
- DescResID := DescID;
- end;
- inherited Add(newRec);
- end;
- function TGLVectorFileFormatsList.FindExt(Ext: string): TGLVectorFileClass;
- var
- i: Integer;
- begin
- Ext := AnsiLowerCase(Ext);
- for i := Count - 1 downto 0 do
- with TGLVectorFileFormat(Items[i]) do
- begin
- if Extension = Ext then
- begin
- Result := VectorFileClass;
- Exit;
- end;
- end;
- Result := nil;
- end;
- function TGLVectorFileFormatsList.FindFromFileName(const filename: string): TGLVectorFileClass;
- 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 TGLVectorFileFormatsList.Remove(AClass: TGLVectorFileClass);
- var
- i: Integer;
- begin
- for i := Count - 1 downto 0 do
- begin
- if TGLVectorFileFormat(Items[i]).VectorFileClass.InheritsFrom(AClass) then
- DeleteAndFree(i);
- end;
- end;
- procedure TGLVectorFileFormatsList.BuildFilterStrings(
- VectorFileClass: TGLVectorFileClass; out descriptions, filters: string;
- formatsThatCanBeOpened: Boolean = True; formatsThatCanBeSaved: Boolean = False);
- var
- k, i: Integer;
- p: TGLVectorFileFormat;
- begin
- descriptions := '';
- filters := '';
- k := 0;
- for i := 0 to Count - 1 do
- begin
- p := TGLVectorFileFormat(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 TGLVectorFileFormatsList.FindExtByIndex(Index: Integer;
- formatsThatCanBeOpened: Boolean = True;
- formatsThatCanBeSaved: Boolean = False): string;
- var
- i: Integer;
- p: TGLVectorFileFormat;
- begin
- Result := '';
- if index > 0 then
- begin
- for i := 0 to Count - 1 do
- begin
- p := TGLVectorFileFormat(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;
- // ------------------
- // ------------------ TGLBaseMeshObject ------------------
- // ------------------
- constructor TGLBaseMeshObject.Create;
- begin
- FVertices := TGLAffineVectorList.Create;
- FNormals := TGLAffineVectorList.Create;
- FVisible := True;
- inherited Create;
- end;
- destructor TGLBaseMeshObject.Destroy;
- begin
- FNormals.Free;
- FVertices.Free;
- inherited;
- end;
- procedure TGLBaseMeshObject.Assign(Source: TPersistent);
- begin
- if Source is TGLBaseMeshObject then
- begin
- FName := TGLBaseMeshObject(Source).Name;
- FVertices.Assign(TGLBaseMeshObject(Source).FVertices);
- FNormals.Assign(TGLBaseMeshObject(Source).FNormals);
- end
- else
- inherited; // Die!
- end;
- procedure TGLBaseMeshObject.WriteToFiler(writer: TGLVirtualWriter);
- 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 TGLBaseMeshObject.ReadFromFiler(reader: TGLVirtualReader);
- 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 TGLBaseMeshObject.Clear;
- begin
- FNormals.Clear;
- FVertices.Clear;
- end;
- procedure TGLBaseMeshObject.ContributeToBarycenter(var currentSum: TAffineVector; var nb: Integer);
- begin
- AddVector(currentSum, FVertices.Sum);
- nb := nb + FVertices.Count;
- end;
- procedure TGLBaseMeshObject.Translate(const delta: TAffineVector);
- begin
- FVertices.Translate(delta);
- end;
- procedure TGLBaseMeshObject.BuildNormals(vertexIndices: TGLIntegerList; Mode: TGLMeshObjectMode;
- normalIndices: TGLIntegerList = nil);
- var
- i, base: Integer;
- n: TAffineVector;
- newNormals: TGLIntegerList;
- 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 := TGLIntegerList.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;
- procedure TGLBaseMeshObject.GenericOrderedBuildNormals(mode: TGLMeshObjectMode);
- var
- i: Integer;
- n: TAffineVector;
- begin
- Normals.Clear;
- Normals.Count := Vertices.Count;
- case mode of
- momTriangles:
- begin
- i := 0;
- while i <= Vertices.Count - 3 do
- with Normals do
- begin
- with Vertices do
- begin
- CalcPlaneNormal(Items[i], Items[i + 1], Items[i + 2], n);
- end;
- with Normals do
- begin
- TranslateItem(i, n);
- TranslateItem(i + 1, n);
- TranslateItem(i + 2, n);
- end;
- Inc(i, 3);
- end;
- end;
- momTriangleStrip:
- begin
- i := 0;
- while i <= Vertices.Count - 3 do
- with Normals do
- begin
- with Vertices do
- begin
- if (i and 1) = 0 then
- CalcPlaneNormal(Items[i], Items[i + 1], Items[i + 2], n)
- else
- CalcPlaneNormal(Items[i], Items[i + 2], Items[i + 1], n);
- end;
- with Normals do
- begin
- TranslateItem(i, n);
- TranslateItem(i + 1, n);
- TranslateItem(i + 2, n);
- end;
- Inc(i, 1);
- end;
- end
- else
- Assert(False);
- end;
- Normals.normalize;
- end;
- function TGLBaseMeshObject.ExtractTriangles(texCoords: TGLAffineVectorList = nil;
- normals: TGLAffineVectorList = nil): TGLAffineVectorList;
- begin
- Result := TGLAffineVectorList.Create;
- if (Vertices.Count mod 3) = 0 then
- begin
- Result.Assign(Vertices);
- if Assigned(normals) then
- normals.Assign(Self.Normals);
- end;
- end;
- procedure TGLBaseMeshObject.SetVertices(const val: TGLAffineVectorList);
- begin
- FVertices.Assign(val);
- end;
- procedure TGLBaseMeshObject.SetNormals(const val: TGLAffineVectorList);
- begin
- FNormals.Assign(val);
- end;
- // ------------------
- // ------------------ TGLSkeletonFrame ------------------
- // ------------------
- constructor TGLSkeletonFrame.CreateOwned(aOwner: TGLSkeletonFrameList);
- begin
- FOwner := aOwner;
- aOwner.Add(Self);
- Create;
- end;
- constructor TGLSkeletonFrame.Create;
- begin
- inherited Create;
- FPosition := TGLAffineVectorList.Create;
- FRotation := TGLAffineVectorList.Create;
- FQuaternion := TGLQuaternionList.Create;
- FTransformMode := sftRotation;
- end;
- destructor TGLSkeletonFrame.Destroy;
- begin
- FlushLocalMatrixList;
- FRotation.Free;
- FPosition.Free;
- FQuaternion.Free;
- inherited Destroy;
- end;
- procedure TGLSkeletonFrame.WriteToFiler(writer: TGLVirtualWriter);
- 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 TGLSkeletonFrame.ReadFromFiler(reader: TGLVirtualReader);
- 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 := TGLSkeletonFrameTransform(ReadInteger);
- end;
- end
- else
- RaiseFilerException(archiveVersion);
- FlushLocalMatrixList;
- end;
- procedure TGLSkeletonFrame.SetPosition(const val: TGLAffineVectorList);
- begin
- FPosition.Assign(val);
- end;
- procedure TGLSkeletonFrame.SetRotation(const val: TGLAffineVectorList);
- begin
- FRotation.Assign(val);
- end;
- procedure TGLSkeletonFrame.SetQuaternion(const val: TGLQuaternionList);
- begin
- FQuaternion.Assign(val);
- end;
- function TGLSkeletonFrame.LocalMatrixList: PMatrixArray;
- var
- i: Integer;
- s, c: Single;
- mat, rmat: TGLMatrix;
- quat: TQuaternion;
- begin
- if not Assigned(FLocalMatrixList) then
- begin
- case FTransformMode of
- sftRotation:
- begin
- FLocalMatrixList := AllocMem(SizeOf(TGLMatrix) * 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(TGLMatrix) * 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 TGLSkeletonFrame.FlushLocalMatrixList;
- begin
- if Assigned(FLocalMatrixList) then
- begin
- FreeMem(FLocalMatrixList);
- FLocalMatrixList := nil;
- end;
- end;
- procedure TGLSkeletonFrame.ConvertQuaternionsToRotations(KeepQuaternions: Boolean = True);
- var
- i: Integer;
- t: TTransformations;
- m: TGLMatrix;
- 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 TGLSkeletonFrame.ConvertRotationsToQuaternions(KeepRotations: Boolean = True);
- var
- i: Integer;
- mat, rmat: TGLMatrix;
- 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;
- // ------------------
- // ------------------ TGLSkeletonFrameList ------------------
- // ------------------
- constructor TGLSkeletonFrameList.CreateOwned(aOwner: TPersistent);
- begin
- FOwner := AOwner;
- Create;
- end;
- destructor TGLSkeletonFrameList.Destroy;
- begin
- Clear;
- inherited;
- end;
- procedure TGLSkeletonFrameList.ReadFromFiler(reader: TGLVirtualReader);
- var
- i: Integer;
- begin
- inherited;
- for i := 0 to Count - 1 do
- Items[i].FOwner := Self;
- end;
- procedure TGLSkeletonFrameList.Clear;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- with Items[i] do
- begin
- FOwner := nil;
- Free;
- end;
- inherited;
- end;
- function TGLSkeletonFrameList.GetSkeletonFrame(Index: Integer): TGLSkeletonFrame;
- begin
- Result := TGLSkeletonFrame(List^[Index]);
- end;
- procedure TGLSkeletonFrameList.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 TGLSkeletonFrameList.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;
- // ------------------
- // ------------------ TGLSkeletonBoneList ------------------
- // ------------------
- constructor TGLSkeletonBoneList.CreateOwned(aOwner: TGLSkeleton);
- begin
- FSkeleton := aOwner;
- Create;
- end;
- constructor TGLSkeletonBoneList.Create;
- begin
- inherited;
- FGlobalMatrix := IdentityHmgMatrix;
- end;
- destructor TGLSkeletonBoneList.Destroy;
- begin
- Clean;
- inherited;
- end;
- procedure TGLSkeletonBoneList.WriteToFiler(writer: TGLVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- // nothing, yet
- end;
- end;
- procedure TGLSkeletonBoneList.ReadFromFiler(reader: TGLVirtualReader);
- 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 TGLSkeletonBoneList.AfterObjectCreatedByReader(Sender: TObject);
- begin
- with (Sender as TGLSkeletonBone) do
- begin
- FOwner := Self;
- FSkeleton := Self.Skeleton;
- end;
- end;
- function TGLSkeletonBoneList.GetSkeletonBone(Index: Integer): TGLSkeletonBone;
- begin
- Result := TGLSkeletonBone(List^[Index]);
- end;
- function TGLSkeletonBoneList.BoneByID(anID: Integer): TGLSkeletonBone;
- 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 TGLSkeletonBoneList.BoneByName(const aName: string): TGLSkeletonBone;
- 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 TGLSkeletonBoneList.BoneCount: Integer;
- var
- i: Integer;
- begin
- Result := 1;
- for i := 0 to Count - 1 do
- Inc(Result, Items[i].BoneCount);
- end;
- procedure TGLSkeletonBoneList.PrepareGlobalMatrices;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- Items[i].PrepareGlobalMatrices;
- end;
- // ------------------
- // ------------------ TGLSkeletonRootBoneList ------------------
- // ------------------
- procedure TGLSkeletonRootBoneList.WriteToFiler(writer: TGLVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- // nothing, yet
- end;
- end;
- procedure TGLSkeletonRootBoneList.ReadFromFiler(reader: TGLVirtualReader);
- 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 TGLSkeletonRootBoneList.BuildList(var mrci: TGLRenderContextInfo);
- var
- i: Integer;
- begin
- // root node setups and restore OpenGL stuff
- mrci.GLStates.Disable(stColorMaterial);
- mrci.GLStates.Disable(stLighting);
- gl.Color3f(1, 1, 1);
- // render root-bones
- for i := 0 to Count - 1 do
- Items[i].BuildList(mrci);
- end;
- // ------------------
- // ------------------ TGLSkeletonBone ------------------
- // ------------------
- constructor TGLSkeletonBone.CreateOwned(aOwner: TGLSkeletonBoneList);
- begin
- FOwner := aOwner;
- aOwner.Add(Self);
- FSkeleton := aOwner.Skeleton;
- Create;
- end;
- constructor TGLSkeletonBone.Create;
- begin
- FColor := $FFFFFFFF; // opaque white
- inherited;
- end;
- destructor TGLSkeletonBone.Destroy;
- begin
- if Assigned(Owner) then
- Owner.Remove(Self);
- inherited Destroy;
- end;
- procedure TGLSkeletonBone.WriteToFiler(writer: TGLVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- WriteString(FName);
- WriteInteger(FBoneID);
- WriteInteger(Integer(FColor));
- end;
- end;
- procedure TGLSkeletonBone.ReadFromFiler(reader: TGLVirtualReader);
- 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 TGLSkeletonBone.BuildList(var mrci: TGLRenderContextInfo);
- procedure IssueColor(Color: Cardinal);
- begin
- gl.Color4f(GetRValue(Color) / 255, GetGValue(Color) / 255, GetBValue(Color) / 255, ((Color shr 24) and 255) / 255);
- end;
- var
- i: Integer;
- begin
- // point for self
- mrci.GLStates.PointSize := 5;
- gl.Begin_(GL_POINTS);
- IssueColor(Color);
- gl.Vertex3fv(@GlobalMatrix.W.X);
- gl.End_;
- // parent-self bone line
- if Owner is TGLSkeletonBone then
- begin
- gl.Begin_(GL_LINES);
- gl.Vertex3fv(@TGLSkeletonBone(Owner).GlobalMatrix.W.X);
- gl.Vertex3fv(@GlobalMatrix.W.X);
- gl.End_;
- end;
- // render sub-bones
- for i := 0 to Count - 1 do
- Items[i].BuildList(mrci);
- end;
- function TGLSkeletonBone.GetSkeletonBone(Index: Integer): TGLSkeletonBone;
- begin
- Result := TGLSkeletonBone(List^[Index]);
- end;
- procedure TGLSkeletonBone.SetColor(const val: Cardinal);
- begin
- FColor := val;
- end;
- function TGLSkeletonBone.BoneByID(anID: Integer): TGLSkeletonBone;
- begin
- if BoneID = anID then
- Result := Self
- else
- Result := inherited BoneByID(anID);
- end;
- function TGLSkeletonBone.BoneByName(const aName: string): TGLSkeletonBone;
- begin
- if Name = aName then
- Result := Self
- else
- Result := inherited BoneByName(aName);
- end;
- procedure TGLSkeletonBone.Clean;
- begin
- BoneID := 0;
- Name := '';
- inherited;
- end;
- procedure TGLSkeletonBone.PrepareGlobalMatrices;
- begin
- if (Skeleton.FRagDollEnabled) then
- Exit; // ragdoll
- FGlobalMatrix :=
- MatrixMultiply(Skeleton.CurrentFrame.LocalMatrixList^[BoneID],
- TGLSkeletonBoneList(Owner).FGlobalMatrix);
- inherited;
- end;
- procedure TGLSkeletonBone.SetGlobalMatrix(const Matrix: TGLMatrix); // ragdoll
- begin
- FGlobalMatrix := Matrix;
- end;
- procedure TGLSkeletonBone.SetGlobalMatrixForRagDoll(const RagDollMatrix: TGLMatrix);
- // ragdoll
- begin
- FGlobalMatrix := MatrixMultiply(RagDollMatrix,
- Skeleton.Owner.InvAbsoluteMatrix);
- inherited;
- end;
- // ------------------
- // ------------------ TGLSkeletonCollider ------------------
- // ------------------
- constructor TGLSkeletonCollider.Create;
- begin
- inherited;
- FLocalMatrix := IdentityHmgMatrix;
- FGlobalMatrix := IdentityHmgMatrix;
- FAutoUpdate := True;
- end;
- constructor TGLSkeletonCollider.CreateOwned(AOwner: TGLSkeletonColliderList);
- begin
- Create;
- FOwner := AOwner;
- if Assigned(FOwner) then
- FOwner.Add(Self);
- end;
- procedure TGLSkeletonCollider.WriteToFiler(writer: TGLVirtualWriter);
- 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(TGLMatrix));
- end;
- end;
- procedure TGLSkeletonCollider.ReadFromFiler(reader: TGLVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- FBoneID := ReadInteger;
- Read(FLocalMatrix, SizeOf(TGLMatrix));
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TGLSkeletonCollider.AlignCollider;
- var
- mat: TGLMatrix;
- begin
- if Assigned(FBone) then
- begin
- if Owner.Owner is TGLSkeleton then
- if TGLSkeleton(Owner.Owner).Owner is TGLBaseSceneObject then
- mat := MatrixMultiply(FBone.GlobalMatrix,
- TGLBaseSceneObject(TGLSkeleton(Owner.Owner).Owner).AbsoluteMatrix)
- else
- mat := FBone.GlobalMatrix;
- MatrixMultiply(FLocalMatrix, mat, FGlobalMatrix);
- end
- else
- FGlobalMatrix := FLocalMatrix;
- end;
- procedure TGLSkeletonCollider.SetBone(const val: TGLSkeletonBone);
- begin
- if val <> FBone then
- FBone := val;
- end;
- procedure TGLSkeletonCollider.SetLocalMatrix(const val: TGLMatrix);
- begin
- FLocalMatrix := val;
- end;
- // ------------------
- // ------------------ TGLSkeletonColliderList ------------------
- // ------------------
- constructor TGLSkeletonColliderList.CreateOwned(aOwner: TPersistent);
- begin
- Create;
- FOwner := aOwner;
- end;
- destructor TGLSkeletonColliderList.Destroy;
- begin
- Clear;
- inherited;
- end;
- function TGLSkeletonColliderList.GetSkeletonCollider(Index: Integer): TGLSkeletonCollider;
- begin
- Result := TGLSkeletonCollider(inherited Get(index));
- end;
- procedure TGLSkeletonColliderList.ReadFromFiler(reader: TGLVirtualReader);
- var
- i: Integer;
- begin
- inherited;
- for i := 0 to Count - 1 do
- begin
- Items[i].FOwner := Self;
- if (Owner is TGLSkeleton) and (Items[i].FBoneID <> -1) then
- Items[i].Bone := TGLSkeleton(Owner).BoneByID(Items[i].FBoneID);
- end;
- end;
- procedure TGLSkeletonColliderList.Clear;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- begin
- Items[i].FOwner := nil;
- Items[i].Free;
- end;
- inherited;
- end;
- procedure TGLSkeletonColliderList.AlignColliders;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- if Items[i].AutoUpdate then
- Items[i].AlignCollider;
- end;
- // ------------------
- // ------------------ TGLSkeleton ------------------
- // ------------------
- constructor TGLSkeleton.CreateOwned(AOwner: TGLBaseMesh);
- begin
- FOwner := aOwner;
- Create;
- end;
- constructor TGLSkeleton.Create;
- begin
- inherited Create;
- FRootBones := TGLSkeletonRootBoneList.CreateOwned(Self);
- FFrames := TGLSkeletonFrameList.CreateOwned(Self);
- FColliders := TGLSkeletonColliderList.CreateOwned(Self);
- end;
- destructor TGLSkeleton.Destroy;
- begin
- FlushBoneByIDCache;
- FCurrentFrame.Free;
- FFrames.Free;
- FRootBones.Free;
- FColliders.Free;
- inherited Destroy;
- end;
- procedure TGLSkeleton.WriteToFiler(writer: TGLVirtualWriter);
- 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 TGLSkeleton.ReadFromFiler(reader: TGLVirtualReader);
- 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 TGLSkeleton.SetRootBones(const val: TGLSkeletonRootBoneList);
- begin
- FRootBones.Assign(val);
- end;
- procedure TGLSkeleton.SetFrames(const val: TGLSkeletonFrameList);
- begin
- FFrames.Assign(val);
- end;
- function TGLSkeleton.GetCurrentFrame: TGLSkeletonFrame;
- begin
- if not Assigned(FCurrentFrame) then
- FCurrentFrame := TGLSkeletonFrame(FFrames.Items[0].CreateClone);
- Result := FCurrentFrame;
- end;
- procedure TGLSkeleton.SetCurrentFrame(val: TGLSkeletonFrame);
- begin
- if Assigned(FCurrentFrame) then
- FCurrentFrame.Free;
- FCurrentFrame := TGLSkeletonFrame(val.CreateClone);
- end;
- procedure TGLSkeleton.SetColliders(const val: TGLSkeletonColliderList);
- begin
- FColliders.Assign(val);
- end;
- procedure TGLSkeleton.FlushBoneByIDCache;
- begin
- FBonesByIDCache.Free;
- FBonesByIDCache := nil;
- end;
- function TGLSkeleton.BoneByID(anID: Integer): TGLSkeletonBone;
- procedure CollectBones(Bone: TGLSkeletonBone);
- 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 := TGLSkeletonBone(FBonesByIDCache[anID])
- end;
- function TGLSkeleton.BoneByName(const aName: string): TGLSkeletonBone;
- begin
- Result := RootBones.BoneByName(aName);
- end;
- function TGLSkeleton.BoneCount: Integer;
- begin
- Result := RootBones.BoneCount;
- end;
- procedure TGLSkeleton.MorphTo(frameIndex: Integer);
- begin
- CurrentFrame := Frames[frameIndex];
- end;
- procedure TGLSkeleton.MorphTo(frame: TGLSkeletonFrame);
- begin
- CurrentFrame := frame;
- end;
- procedure TGLSkeleton.Lerp(frameIndex1, frameIndex2: Integer; lerpFactor: Single);
- begin
- if Assigned(FCurrentFrame) then
- FCurrentFrame.Free;
- FCurrentFrame := TGLSkeletonFrame.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 TGLSkeleton.BlendedLerps(const lerpInfos: array of TGLBlendedLerpInfo);
- var
- i, n: Integer;
- blendPositions: TGLAffineVectorList;
- blendRotations: TGLAffineVectorList;
- blendQuaternions: TGLQuaternionList;
- 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 := TGLSkeletonFrame.Create;
- FCurrentFrame.TransformMode :=
- Frames[lerpInfos[i].frameIndex1].TransformMode;
- with FCurrentFrame do
- begin
- blendPositions := TGLAffineVectorList.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 := TGLAffineVectorList.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 := TGLQuaternionList.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 TGLSkeleton.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 TGLSkeleton.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 TGLSkeleton.MorphMesh(normalize: Boolean);
- var
- i: Integer;
- mesh: TGLBaseMeshObject;
- 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 TGLSkeletonMeshObject) then
- TGLSkeletonMeshObject(mesh).ApplyCurrentSkeletonFrame(normalize);
- end
- else
- for i := 0 to Owner.MeshObjects.Count - 1 do
- begin
- mesh := Owner.MeshObjects.Items[i];
- if (mesh is TGLSkeletonMeshObject) and mesh.Visible then
- TGLSkeletonMeshObject(mesh).ApplyCurrentSkeletonFrame(normalize);
- end
- end;
- end;
- procedure TGLSkeleton.Synchronize(reference: TGLSkeleton);
- begin
- CurrentFrame.Assign(reference.CurrentFrame);
- MorphMesh(True);
- end;
- procedure TGLSkeleton.Clear;
- begin
- FlushBoneByIDCache;
- RootBones.Clean;
- Frames.Clear;
- FCurrentFrame.Free;
- FCurrentFrame := nil;
- FColliders.Clear;
- end;
- procedure TGLSkeleton.StartRagDoll; // ragdoll
- var
- i: Integer;
- mesh: TGLBaseMeshObject;
- 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 TGLSkeletonMeshObject then
- begin
- TGLSkeletonMeshObject(mesh).BackupBoneMatrixInvertedMeshes;
- TGLSkeletonMeshObject(mesh).PrepareBoneMatrixInvertedMeshes;
- end;
- end;
- end;
- end;
- procedure TGLSkeleton.StopRagDoll; // ragdoll
- var
- i: Integer;
- mesh: TGLBaseMeshObject;
- 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 TGLSkeletonMeshObject then
- TGLSkeletonMeshObject(mesh).RestoreBoneMatrixInvertedMeshes;
- end;
- end;
- end;
- // ------------------
- // ------------------ TGLMeshObject ------------------
- // ------------------
- constructor TGLMeshObject.CreateOwned(AOwner: TGLMeshObjectList);
- begin
- FOwner := AOwner;
- Create;
- if Assigned(FOwner) then
- FOwner.Add(Self);
- end;
- constructor TGLMeshObject.Create;
- begin
- FMode := momTriangles;
- FTexCoords := TGLAffineVectorList.Create;
- FLightMapTexCoords := TGLAffineVectorList.Create;
- FColors := TGLVectorList.Create;
- FFaceGroups := TGLFaceGroups.CreateOwned(Self);
- FTexCoordsEx := TList.Create;
- FTangentsTexCoordIndex := 1;
- FBinormalsTexCoordIndex := 2;
- FUseVBO := vGLVectorFileObjectsEnableVBOByDefault;
- inherited;
- end;
- destructor TGLMeshObject.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
- TGLVectorList(FTexCoordsEx[i]).Free;
- FTexCoordsEx.Free;
- if Assigned(FOwner) then
- FOwner.Remove(Self);
- inherited;
- end;
- procedure TGLMeshObject.Assign(Source: TPersistent);
- var
- I: Integer;
- begin
- inherited Assign(Source);
- if Source is TGLMeshObject then
- begin
- FTexCoords.Assign(TGLMeshObject(Source).FTexCoords);
- FLightMapTexCoords.Assign(TGLMeshObject(Source).FLightMapTexCoords);
- FColors.Assign(TGLMeshObject(Source).FColors);
- FFaceGroups.Assign(TGLMeshObject(Source).FFaceGroups);
- FMode := TGLMeshObject(Source).FMode;
- FRenderingOptions := TGLMeshObject(Source).FRenderingOptions;
- FBinormalsTexCoordIndex := TGLMeshObject(Source).FBinormalsTexCoordIndex;
- FTangentsTexCoordIndex := TGLMeshObject(Source).FTangentsTexCoordIndex;
- // Clear FTexCoordsEx.
- for I := 0 to FTexCoordsEx.Count - 1 do
- TGLVectorList(FTexCoordsEx[I]).Free;
- FTexCoordsEx.Count := TGLMeshObject(Source).FTexCoordsEx.Count;
- // Fill FTexCoordsEx.
- for I := 0 to FTexCoordsEx.Count - 1 do
- begin
- FTexCoordsEx[I] := TGLVectorList.Create;
- TGLVectorList(FTexCoordsEx[I]).Assign(TGLMeshObject(Source).FTexCoordsEx[I]);
- end;
- end;
- end;
- procedure TGLMeshObject.WriteToFiler(writer: TGLVirtualWriter);
- 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 TGLMeshObject.ReadFromFiler(reader: TGLVirtualReader);
- var
- i, Count, archiveVersion: Integer;
- lOldLightMapTexCoords: TGLTexPointList;
- 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 := TGLTexPointList.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 := TGLMeshObjectMode(ReadInteger);
- size := ReadInteger;
- ro := 0;
- Read(ro, size);
- FRenderingOptions := TGLMeshObjectRenderingOptions(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 TGLMeshObject.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 TGLMeshObject.ExtractTriangles(texCoords: TGLAffineVectorList = nil;
- Normals: TGLAffineVectorList = nil): TGLAffineVectorList;
- 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 := TGLAffineVectorList.Create;
- ConvertStripToList(Vertices, Result);
- if Assigned(texCoords) then
- ConvertStripToList(Self.TexCoords, texCoords);
- if Assigned(normals) then
- ConvertStripToList(Self.Normals, normals);
- end;
- momFaceGroups:
- begin
- Result := TGLAffineVectorList.Create;
- FaceGroups.AddToTriangles(Result, texCoords, normals);
- end;
- else
- Result := nil;
- Assert(False);
- end;
- end;
- function TGLMeshObject.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 TGLMeshObject.PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
- begin
- FaceGroups.PrepareMaterialLibraryCache(matLib);
- end;
- procedure TGLMeshObject.DropMaterialLibraryCache;
- begin
- FaceGroups.DropMaterialLibraryCache;
- end;
- procedure TGLMeshObject.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 TGLMeshObject.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 TGLMeshObject.GetBarycenter: TGLVector;
- 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 TGLMeshObject.Prepare;
- var
- i: Integer;
- begin
- ValidBuffers := [];
- for i := 0 to FaceGroups.Count - 1 do
- FaceGroups[i].Prepare;
- end;
- function TGLMeshObject.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 TGLMeshObject.SetTexCoords(const val: TGLAffineVectorList);
- begin
- FTexCoords.Assign(val);
- end;
- procedure TGLMeshObject.SetLightmapTexCoords(const val: TGLAffineVectorList);
- begin
- FLightMapTexCoords.Assign(val);
- end;
- procedure TGLMeshObject.SetColors(const val: TGLVectorList);
- begin
- FColors.Assign(val);
- end;
- procedure TGLMeshObject.SetTexCoordsEx(Index: Integer; const val: TGLVectorList);
- begin
- TexCoordsEx[index].Assign(val);
- end;
- function TGLMeshObject.GetTexCoordsEx(Index: Integer): TGLVectorList;
- var
- i: Integer;
- begin
- if index > FTexCoordsEx.Count - 1 then
- for i := FTexCoordsEx.Count - 1 to index do
- FTexCoordsEx.Add(TGLVectorList.Create);
- Result := TGLVectorList(FTexCoordsEx[index]);
- end;
- procedure TGLMeshObject.SetBinormals(const val: TGLVectorList);
- begin
- Binormals.Assign(val);
- end;
- function TGLMeshObject.GetBinormals: TGLVectorList;
- begin
- Result := TexCoordsEx[BinormalsTexCoordIndex];
- end;
- procedure TGLMeshObject.SetBinormalsTexCoordIndex(const val: Integer);
- begin
- Assert(val >= 0);
- if val <> FBinormalsTexCoordIndex then
- begin
- FBinormalsTexCoordIndex := val;
- end;
- end;
- procedure TGLMeshObject.SetTangents(const val: TGLVectorList);
- begin
- Tangents.Assign(val);
- end;
- function TGLMeshObject.GetTangents: TGLVectorList;
- begin
- Result := TexCoordsEx[TangentsTexCoordIndex];
- end;
- procedure TGLMeshObject.SetTangentsTexCoordIndex(const val: Integer);
- begin
- Assert(val >= 0);
- if val <> FTangentsTexCoordIndex then
- begin
- FTangentsTexCoordIndex := val;
- end;
- end;
- procedure TGLMeshObject.GetTriangleData(tri: Integer; list: TGLAffineVectorList; var v0, v1, v2: TAffineVector);
- var
- i, LastCount, Count: Integer;
- fg: TFGVertexIndexList;
- 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 := TFGVertexIndexList(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 TGLMeshObject.GetTriangleData(tri: Integer; list: TGLVectorList; var v0, v1, v2: TGLVector);
- var
- i, LastCount, Count: Integer;
- fg: TFGVertexIndexList;
- 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 := TFGVertexIndexList(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 TGLMeshObject.SetTriangleData(tri: Integer; list: TGLAffineVectorList; const v0, v1, v2: TAffineVector);
- var
- i, LastCount, Count: Integer;
- fg: TFGVertexIndexList;
- 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 := TFGVertexIndexList(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 TGLMeshObject.SetTriangleData(tri: Integer; list: TGLVectorList; const v0, v1, v2: TGLVector);
- var
- i, LastCount, Count: Integer;
- fg: TFGVertexIndexList;
- 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 := TFGVertexIndexList(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 TGLMeshObject.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 TGLMeshObject.SetValidBuffers(Value: TGLVBOBuffers);
- 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 TGLMeshObject.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 TGLVector;
- 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 TGLMeshObject.DeclareArraysToOpenGL(var mrci: TGLRenderContextInfo; 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 GL.ARB_vertex_buffer_object
- and not mrci.GLStates.InsideList;
- 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;
- gl.EnableClientState(GL_NORMAL_ARRAY);
- gl.NormalPointer(GL_FLOAT, 0, lists[1]);
- end
- else
- gl.DisableClientState(GL_NORMAL_ARRAY);
- if (Colors.Count > 0) and (not mrci.ignoreMaterials) then
- begin
- if FUseVBO then
- FColorsVBO.Bind;
- gl.EnableClientState(GL_COLOR_ARRAY);
- gl.ColorPointer(4, GL_FLOAT, 0, lists[2]);
- end
- else
- gl.DisableClientState(GL_COLOR_ARRAY);
- if TexCoords.Count > 0 then
- begin
- if FUseVBO then
- FTexCoordsVBO[0].Bind;
- xgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
- xgl.TexCoordPointer(2, GL_FLOAT, SizeOf(TAffineVector), lists[3]);
- end
- else
- xgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
- if gl.ARB_multitexture then
- begin
- if LightMapTexCoords.Count > 0 then
- begin
- if FUseVBO then
- FLightmapTexCoordsVBO.Bind;
- gl.ClientActiveTexture(GL_TEXTURE1);
- gl.TexCoordPointer(2, GL_FLOAT, SizeOf(TAffineVector), lists[4]);
- gl.EnableClientState(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;
- gl.ClientActiveTexture(GL_TEXTURE0 + i);
- gl.TexCoordPointer(4, GL_FLOAT, SizeOf(TGLVector), tlists[i]);
- gl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
- end;
- end;
- gl.ClientActiveTexture(GL_TEXTURE0);
- end;
- end
- else
- begin
- gl.DisableClientState(GL_NORMAL_ARRAY);
- gl.DisableClientState(GL_COLOR_ARRAY);
- xgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
- end;
- if Vertices.Count > 0 then
- begin
- if FUseVBO then
- FVerticesVBO.Bind;
- gl.EnableClientState(GL_VERTEX_ARRAY);
- gl.VertexPointer(3, GL_FLOAT, 0, lists[0]);
- end
- else
- gl.DisableClientState(GL_VERTEX_ARRAY);
- if gl.EXT_compiled_vertex_array and (LightMapTexCoords.Count = 0) and not FUseVBO then
- gl.LockArrays(0, Vertices.Count);
- FLastLightMapIndex := -1;
- FArraysDeclared := True;
- FLightMapArrayEnabled := False;
- if mrci.drawState <> dsPicking then
- FLastXOpenGLTexMapping := xgl.GetBitWiseMapping;
- end
- else
- begin
- if not mrci.ignoreMaterials and not (mrci.drawState = dsPicking) then
- if TexCoords.Count > 0 then
- begin
- currentMapping := xgl.GetBitWiseMapping;
- if FLastXOpenGLTexMapping <> currentMapping then
- begin
- xgl.EnableClientState(GL_TEXTURE_COORD_ARRAY);
- xgl.TexCoordPointer(2, GL_FLOAT, SizeOf(TAffineVector), TexCoords.List);
- FLastXOpenGLTexMapping := currentMapping;
- end;
- end;
- end;
- end;
- procedure TGLMeshObject.DisableOpenGLArrays(var mrci: TGLRenderContextInfo);
- var
- i: Integer;
- begin
- if FArraysDeclared then
- begin
- DisableLightMapArray(mrci);
- if gl.EXT_compiled_vertex_array and (LightMapTexCoords.Count = 0) and not FUseVBO then
- gl.UnLockArrays;
- if Vertices.Count > 0 then
- gl.DisableClientState(GL_VERTEX_ARRAY);
- if not mrci.ignoreMaterials then
- begin
- if Normals.Count > 0 then
- gl.DisableClientState(GL_NORMAL_ARRAY);
- if (Colors.Count > 0) and (not mrci.ignoreMaterials) then
- gl.DisableClientState(GL_COLOR_ARRAY);
- if TexCoords.Count > 0 then
- xgl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
- if gl.ARB_multitexture then
- begin
- if LightMapTexCoords.Count > 0 then
- begin
- gl.ClientActiveTexture(GL_TEXTURE1);
- gl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
- end;
- for i := 0 to FTexCoordsEx.Count - 1 do
- begin
- if TexCoordsEx[i].Count > 0 then
- begin
- gl.ClientActiveTexture(GL_TEXTURE0 + i);
- gl.DisableClientState(GL_TEXTURE_COORD_ARRAY);
- end;
- end;
- gl.ClientActiveTexture(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 TGLMeshObject.EnableLightMapArray(var mrci: TGLRenderContextInfo);
- begin
- if GL.ARB_multitexture and (not mrci.ignoreMaterials) then
- begin
- Assert(FArraysDeclared);
- if not FLightMapArrayEnabled then
- begin
- mrci.GLStates.ActiveTexture := 1;
- mrci.GLStates.ActiveTextureEnabled[ttTexture2D] := True;
- mrci.GLStates.ActiveTexture := 0;
- FLightMapArrayEnabled := True;
- end;
- end;
- end;
- procedure TGLMeshObject.DisableLightMapArray(var mrci: TGLRenderContextInfo);
- begin
- if GL.ARB_multitexture and FLightMapArrayEnabled then
- begin
- mrci.GLStates.ActiveTexture := 1;
- mrci.GLStates.ActiveTextureEnabled[ttTexture2D] := False;
- mrci.GLStates.ActiveTexture := 0;
- FLightMapArrayEnabled := False;
- end;
- end;
- procedure TGLMeshObject.PrepareBuildList(var mrci: TGLRenderContextInfo);
- var
- i: Integer;
- begin
- if (Mode = momFaceGroups) and Assigned(mrci.materialLibrary) then
- begin
- for i := 0 to FaceGroups.Count - 1 do
- with TGLFaceGroup(FaceGroups.List^[i]) do
- begin
- if MaterialCache <> nil then
- MaterialCache.PrepareBuildList;
- end;
- end;
- end;
- procedure TGLMeshObject.BufferArrays;
- const
- BufferUsage = GL_DYNAMIC_DRAW;
- var
- I: integer;
- begin
- if Vertices.Count > 0 then
- begin
- if not Assigned(FVerticesVBO) then
- FVerticesVBO := TGLVBOArrayBufferHandle.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 := TGLVBOArrayBufferHandle.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 := TGLVBOArrayBufferHandle.Create;
- FColorsVBO.AllocateHandle;
- if FColorsVBO.IsDataNeedUpdate then
- begin
- FColorsVBO.BindBufferData(Colors.list, SizeOf(TGLVector) * 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] := TGLVBOArrayBufferHandle.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 := TGLVBOArrayBufferHandle.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] := TGLVBOArrayBufferHandle.Create;
- FTexCoordsVBO[i].AllocateHandle;
- if FTexCoordsVBO[i].IsDataNeedUpdate then
- begin
- FTexCoordsVBO[i].BindBufferData(TexCoordsEx[i].list, SizeOf(TGLVector) * TexCoordsEx[i].Count, BufferUsage);
- FTexCoordsVBO[i].NotifyDataUpdated;
- FTexCoordsVBO[i].UnBind;
- end;
- end;
- Include(FValidBuffers, vbTexCoordsEx);
- end;
- gl.CheckError;
- end;
- procedure TGLMeshObject.BuildList(var mrci: TGLRenderContextInfo);
- var
- i, j, groupID, nbGroups: Integer;
- gotNormals, gotTexCoords, gotColor: Boolean;
- gotTexCoordsEx: array of Boolean;
- libMat: TGLLibMaterial;
- fg: TGLFaceGroup;
- begin
- // Make sure no VBO is bound and states enabled
- FArraysDeclared := False;
- FLastXOpenGLTexMapping := 0;
- gotColor := (Vertices.Count = Colors.Count);
- if gotColor then
- begin
- mrci.GLStates.Enable(stColorMaterial);
- gl.ColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
- mrci.GLStates.SetGLMaterialColors(cmFront, clrBlack, clrGray20, clrGray80, clrBlack, 0);
- mrci.GLStates.SetGLMaterialColors(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
- gl.Begin_(GL_TRIANGLES)
- else
- gl.Begin_(GL_TRIANGLE_STRIP);
- for i := 0 to Vertices.Count - 1 do
- begin
- if gotNormals then
- gl.Normal3fv(@Normals.List[i]);
- if gotColor then
- gl.Color4fv(@Colors.List[i]);
- if FTexCoordsEx.Count > 0 then
- begin
- if gotTexCoordsEx[0] then
- gl.MultiTexCoord4fv(GL_TEXTURE0, @TexCoordsEx[0].List[i])
- else if gotTexCoords then
- xgl.TexCoord2fv(@TexCoords.List[i]);
- for j := 1 to FTexCoordsEx.Count - 1 do
- if gotTexCoordsEx[j] then
- gl.MultiTexCoord4fv(GL_TEXTURE0 + j, @TexCoordsEx[j].list[i]);
- end
- else
- begin
- if gotTexCoords then
- xgl.TexCoord2fv(@TexCoords.List[i]);
- end;
- gl.Vertex3fv(@Vertices.List[i]);
- end;
- gl.End_;
- 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.GLStates.States) then
- begin
- if not mrci.bufferFaceCull then
- mrci.GLStates.Disable(stCullFace);
- end
- else
- begin
- if mrci.bufferFaceCull then
- mrci.GLStates.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;
- // ------------------
- // ------------------ TGLMeshObjectList ------------------
- // ------------------
- constructor TGLMeshObjectList.CreateOwned(aOwner: TGLBaseMesh);
- begin
- FOwner := AOwner;
- Create;
- end;
- destructor TGLMeshObjectList.Destroy;
- begin
- Clear;
- inherited;
- end;
- procedure TGLMeshObjectList.ReadFromFiler(reader: TGLVirtualReader);
- var
- i: Integer;
- mesh: TGLMeshObject;
- begin
- inherited;
- for i := 0 to Count - 1 do
- begin
- mesh := Items[i];
- mesh.FOwner := Self;
- if mesh is TGLSkeletonMeshObject then
- TGLSkeletonMeshObject(mesh).PrepareBoneMatrixInvertedMeshes;
- end;
- end;
- procedure TGLMeshObjectList.PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TGLMeshObject(List^[i]).PrepareMaterialLibraryCache(matLib);
- end;
- procedure TGLMeshObjectList.DropMaterialLibraryCache;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TGLMeshObject(List^[i]).DropMaterialLibraryCache;
- end;
- procedure TGLMeshObjectList.PrepareBuildList(var mrci: TGLRenderContextInfo);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- with Items[i] do
- if Visible then
- PrepareBuildList(mrci);
- end;
- procedure TGLMeshObjectList.BuildList(var mrci: TGLRenderContextInfo);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- with Items[i] do
- if Visible then
- BuildList(mrci);
- end;
- procedure TGLMeshObjectList.MorphTo(morphTargetIndex: Integer);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- if Items[i] is TGLMorphableMeshObject then
- TGLMorphableMeshObject(Items[i]).MorphTo(morphTargetIndex);
- end;
- procedure TGLMeshObjectList.Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- if Items[i] is TGLMorphableMeshObject then
- TGLMorphableMeshObject(Items[i]).Lerp(morphTargetIndex1, morphTargetIndex2, lerpFactor);
- end;
- function TGLMeshObjectList.MorphTargetCount: Integer;
- var
- i: Integer;
- begin
- Result := MaxInt;
- for i := 0 to Count - 1 do
- if Items[i] is TGLMorphableMeshObject then
- with TGLMorphableMeshObject(Items[i]) do
- if Result > MorphTargets.Count then
- Result := MorphTargets.Count;
- if Result = MaxInt then
- Result := 0;
- end;
- procedure TGLMeshObjectList.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 TGLMeshObjectList.GetMeshObject(Index: Integer): TGLMeshObject;
- begin
- Result := TGLMeshObject(List^[Index]);
- end;
- procedure TGLMeshObjectList.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 TGLMeshObjectList.Translate(const delta: TAffineVector);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- GetMeshObject(i).Translate(delta);
- end;
- function TGLMeshObjectList.ExtractTriangles(texCoords: TGLAffineVectorList = nil;
- normals: TGLAffineVectorList = nil): TGLAffineVectorList;
- var
- i: Integer;
- obj: TGLMeshObject;
- objTris: TGLAffineVectorList;
- objTexCoords: TGLAffineVectorList;
- objNormals: TGLAffineVectorList;
- begin
- Result := TGLAffineVectorList.Create;
- Result.AdjustCapacityToAtLeast(Self.TriangleCount * 3);
- if Assigned(texCoords) then
- objTexCoords := TGLAffineVectorList.Create
- else
- objTexCoords := nil;
- if Assigned(normals) then
- objNormals := TGLAffineVectorList.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 TGLMeshObjectList.TriangleCount: Integer;
- var
- i: Integer;
- begin
- Result := 0;
- for i := 0 to Count - 1 do
- Result := Result + Items[i].TriangleCount;
- end;
- function TGLMeshObjectList.Area: Single;
- var
- i: Integer;
- Tri: TFaceRec;
- List: TGLAffineVectorList;
- begin
- Result := 0;
- List := Self.ExtractTriangles;
- if List.Count > 0 then
- try
- i := 0;
- while i < List.Count do
- begin
- Tri.Normal := CalcPlaneNormal(List[i], List[i+1], List[i+2]);
- Tri.V1 := VectorTransform(List[i], TGLBaseSceneObject(Owner).AbsoluteMatrix);
- Tri.V2 := VectorTransform(List[i+1], TGLBaseSceneObject(Owner).AbsoluteMatrix);
- Tri.V3 := VectorTransform(List[i+2], TGLBaseSceneObject(Owner).AbsoluteMatrix);
- Inc(i, 3);
- Result := Result + TriangleArea(Tri.V1, Tri.V2, Tri.V3);
- end;
- finally
- List.Free();
- end;
- end;
- function TGLMeshObjectList.Volume: Single;
- var
- i: Integer;
- Tri: TFaceRec;
- List: TGLAffineVectorList;
- begin
- Result := 0;
- List := Self.ExtractTriangles;
- if List.Count > 0 then
- try
- i := 0;
- while i < List.Count do
- begin
- Tri.Normal := CalcPlaneNormal(List[i], List[i+1], List[i+2]);
- Tri.V1 := VectorTransform(List[i], TGLBaseSceneObject(Owner).AbsoluteMatrix);
- Tri.V2 := VectorTransform(List[i+1], TGLBaseSceneObject(Owner).AbsoluteMatrix);
- Tri.V3 := VectorTransform(List[i+2], TGLBaseSceneObject(Owner).AbsoluteMatrix);
- Inc(i, 3);
- Result := Result + VectorDotProduct(Tri.V1, VectorCrossProduct(Tri.V2, Tri.V3));
- end;
- Result := Result / 6;
- finally
- List.Free();
- end;
- end;
- procedure TGLMeshObjectList.Prepare;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- Items[i].Prepare;
- end;
- function TGLMeshObjectList.FindMeshByName(const MeshName: string): TGLMeshObject;
- 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 TGLMeshObjectList.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 TGLMeshObjectList.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 TGLMeshObjectList.SetUseVBO(const Value: Boolean);
- var
- I: Integer;
- begin
- if Count <> 0 then
- for I := 0 to Count - 1 do
- GetMeshObject(I).SetUseVBO(Value);
- end;
- // ------------------
- // ------------------ TGLMeshMorphTarget ------------------
- // ------------------
- constructor TGLMeshMorphTarget.CreateOwned(AOwner: TGLMeshMorphTargetList);
- begin
- FOwner := AOwner;
- Create;
- if Assigned(FOwner) then
- FOwner.Add(Self);
- end;
- destructor TGLMeshMorphTarget.Destroy;
- begin
- if Assigned(FOwner) then
- FOwner.Remove(Self);
- inherited;
- end;
- procedure TGLMeshMorphTarget.WriteToFiler(writer: TGLVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- // nothing
- end;
- end;
- procedure TGLMeshMorphTarget.ReadFromFiler(reader: TGLVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- // nothing
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- // ------------------
- // ------------------ TGLMeshMorphTargetList ------------------
- // ------------------
- constructor TGLMeshMorphTargetList.CreateOwned(aOwner: TPersistent);
- begin
- FOwner := AOwner;
- Create;
- end;
- destructor TGLMeshMorphTargetList.Destroy;
- begin
- Clear;
- inherited;
- end;
- procedure TGLMeshMorphTargetList.ReadFromFiler(reader: TGLVirtualReader);
- var
- i: Integer;
- begin
- inherited;
- for i := 0 to Count - 1 do
- Items[i].FOwner := Self;
- end;
- procedure TGLMeshMorphTargetList.Translate(const delta: TAffineVector);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- Items[i].Translate(delta);
- end;
- procedure TGLMeshMorphTargetList.Clear;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- with Items[i] do
- begin
- FOwner := nil;
- Free;
- end;
- inherited;
- end;
- function TGLMeshMorphTargetList.GeTGLMeshMorphTarget(Index: Integer): TGLMeshMorphTarget;
- begin
- Result := TGLMeshMorphTarget(List^[Index]);
- end;
- // ------------------
- // ------------------ TGLMorphableMeshObject ------------------
- // ------------------
- constructor TGLMorphableMeshObject.Create;
- begin
- inherited;
- FMorphTargets := TGLMeshMorphTargetList.CreateOwned(Self);
- end;
- destructor TGLMorphableMeshObject.Destroy;
- begin
- FMorphTargets.Free;
- inherited;
- end;
- procedure TGLMorphableMeshObject.WriteToFiler(writer: TGLVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- FMorphTargets.WriteToFiler(writer);
- end;
- end;
- procedure TGLMorphableMeshObject.ReadFromFiler(reader: TGLVirtualReader);
- 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 TGLMorphableMeshObject.Clear;
- begin
- inherited;
- FMorphTargets.Clear;
- end;
- procedure TGLMorphableMeshObject.Translate(const delta: TAffineVector);
- begin
- inherited;
- MorphTargets.Translate(delta);
- ValidBuffers := ValidBuffers - [vbVertices];
- end;
- procedure TGLMorphableMeshObject.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 TGLMorphableMeshObject.Lerp(morphTargetIndex1, morphTargetIndex2: Integer; lerpFactor: Single);
- var
- mt1, mt2: TGLMeshMorphTarget;
- 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;
- // ------------------
- // ------------------ TGLSkeletonMeshObject ------------------
- // ------------------
- constructor TGLSkeletonMeshObject.Create;
- begin
- FBoneMatrixInvertedMeshes := TList.Create;
- FBackupInvertedMeshes := TList.Create; // ragdoll
- inherited Create;
- end;
- destructor TGLSkeletonMeshObject.Destroy;
- begin
- Clear;
- FBoneMatrixInvertedMeshes.Free;
- FBackupInvertedMeshes.Free;
- inherited Destroy;
- end;
- procedure TGLSkeletonMeshObject.WriteToFiler(writer: TGLVirtualWriter);
- 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(TGLVertexBoneWeight));
- end;
- end;
- procedure TGLSkeletonMeshObject.ReadFromFiler(reader: TGLVirtualReader);
- 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(TGLVertexBoneWeight));
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TGLSkeletonMeshObject.Clear;
- var
- i: Integer;
- begin
- inherited;
- FVerticeBoneWeightCount := 0;
- FBonesPerVertex := 0;
- ResizeVerticesBonesWeights;
- for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
- TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
- FBoneMatrixInvertedMeshes.Clear;
- end;
- procedure TGLSkeletonMeshObject.SetVerticeBoneWeightCount(const val: Integer);
- begin
- if val <> FVerticeBoneWeightCount then
- begin
- FVerticeBoneWeightCount := val;
- if FVerticeBoneWeightCount > FVerticeBoneWeightCapacity then
- VerticeBoneWeightCapacity := FVerticeBoneWeightCount + 16;
- FLastVerticeBoneWeightCount := FVerticeBoneWeightCount;
- end;
- end;
- procedure TGLSkeletonMeshObject.SetVerticeBoneWeightCapacity(const val: Integer);
- begin
- if val <> FVerticeBoneWeightCapacity then
- begin
- FVerticeBoneWeightCapacity := val;
- ResizeVerticesBonesWeights;
- end;
- end;
- procedure TGLSkeletonMeshObject.SetBonesPerVertex(const val: Integer);
- begin
- if val <> FBonesPerVertex then
- begin
- FBonesPerVertex := val;
- ResizeVerticesBonesWeights;
- end;
- end;
- procedure TGLSkeletonMeshObject.ResizeVerticesBonesWeights;
- var
- n, m, i, j: Integer;
- newArea: PGLVerticesBoneWeights;
- 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(PGLVertexBoneWeightArray));
- newArea[0] := AllocMem(n * SizeOf(TGLVertexBoneWeight));
- for i := 1 to VerticeBoneWeightCapacity - 1 do
- newArea[i] := PGLVertexBoneWeightArray(Cardinal(newArea[0]) +
- Cardinal(i * SizeOf(TGLVertexBoneWeight) * 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 TGLSkeletonMeshObject.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 TGLSkeletonMeshObject.AddWeightedBones(const boneIDs: TGLVertexBoneWeightDynArray);
- 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 TGLSkeletonMeshObject.FindOrAdd(BoneID: Integer; const vertex, normal: TAffineVector): Integer;
- var
- i: Integer;
- dynArray: TGLVertexBoneWeightDynArray;
- 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 TGLSkeletonMeshObject.FindOrAdd(const boneIDs: TGLVertexBoneWeightDynArray; 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 TGLSkeletonMeshObject.PrepareBoneMatrixInvertedMeshes;
- var
- i, k, boneIndex: Integer;
- invMesh: TGLBaseMeshObject;
- invMat: TGLMatrix;
- Bone: TGLSkeletonBone;
- p: TGLVector;
- begin
- // cleanup existing stuff
- for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
- TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
- FBoneMatrixInvertedMeshes.Clear;
- // calculate
- for k := 0 to BonesPerVertex - 1 do
- begin
- invMesh := TGLBaseMeshObject.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 TGLSkeletonMeshObject.BackupBoneMatrixInvertedMeshes; // ragdoll
- var
- i: Integer;
- bm: TGLBaseMeshObject;
- begin
- // cleanup existing stuff
- for i := 0 to FBackupInvertedMeshes.Count - 1 do
- TGLBaseMeshObject(FBackupInvertedMeshes[i]).Free;
- FBackupInvertedMeshes.Clear;
- // copy current stuff
- for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
- begin
- bm := TGLBaseMeshObject.Create;
- bm.Assign(TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]));
- FBackupInvertedMeshes.Add(bm);
- TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
- end;
- FBoneMatrixInvertedMeshes.Clear;
- end;
- procedure TGLSkeletonMeshObject.RestoreBoneMatrixInvertedMeshes; // ragdoll
- var
- i: Integer;
- bm: TGLBaseMeshObject;
- begin
- // cleanup existing stuff
- for i := 0 to FBoneMatrixInvertedMeshes.Count - 1 do
- TGLBaseMeshObject(FBoneMatrixInvertedMeshes[i]).Free;
- FBoneMatrixInvertedMeshes.Clear;
- // restore the backup
- for i := 0 to FBackupInvertedMeshes.Count - 1 do
- begin
- bm := TGLBaseMeshObject.Create;
- bm.Assign(TGLBaseMeshObject(FBackupInvertedMeshes[i]));
- FBoneMatrixInvertedMeshes.Add(bm);
- TGLBaseMeshObject(FBackupInvertedMeshes[i]).Free;
- end;
- FBackupInvertedMeshes.Clear;
- end;
- procedure TGLSkeletonMeshObject.ApplyCurrentSkeletonFrame(normalize: Boolean);
- var
- i, j, BoneID: Integer;
- refVertices, refNormals: TGLAffineVectorList;
- n, nt: TGLVector;
- Bone: TGLSkeletonBone;
- Skeleton: TGLSkeleton;
- tempvert, tempnorm: TAffineVector;
- begin
- with TGLBaseMeshObject(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 TGLBaseMeshObject(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;
- // ------------------
- // ------------------ TGLFaceGroup ------------------
- // ------------------
- constructor TGLFaceGroup.CreateOwned(AOwner: TGLFaceGroups);
- begin
- FOwner := AOwner;
- FLightMapIndex := -1;
- Create;
- if Assigned(FOwner) then
- FOwner.Add(Self);
- end;
- destructor TGLFaceGroup.Destroy;
- begin
- if Assigned(FOwner) then
- FOwner.Remove(Self);
- inherited;
- end;
- procedure TGLFaceGroup.WriteToFiler(writer: TGLVirtualWriter);
- 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 TGLFaceGroup.ReadFromFiler(reader: TGLVirtualReader);
- 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 TGLFaceGroup.AttachLightmap(lightMap: TGLTexture; var mrci: TGLRenderContextInfo);
- begin
- if GL.ARB_multitexture then
- with lightMap do
- begin
- Assert(Image.NativeTextureTarget = ttTexture2D);
- mrci.GLStates.TextureBinding[1, ttTexture2D] := Handle;
- gl.TexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- mrci.GLStates.ActiveTexture := 0;
- end;
- end;
- procedure TGLFaceGroup.AttachOrDetachLightmap(var mrci: TGLRenderContextInfo);
- var
- libMat: TGLLibMaterial;
- begin
- if GL.ARB_multitexture then
- begin
- 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 < TGLMaterialLibrary(mrci.LightmapLibrary).Materials.Count);
- libMat := TGLMaterialLibrary(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;
- end;
- procedure TGLFaceGroup.PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
- begin
- if (FMaterialName <> '') and (matLib <> nil) then
- FMaterialCache := matLib.Materials.GetLibMaterialByName(FMaterialName)
- else
- FMaterialCache := nil;
- end;
- procedure TGLFaceGroup.DropMaterialLibraryCache;
- begin
- FMaterialCache := nil;
- end;
- procedure TGLFaceGroup.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
- aNormals: TGLAffineVectorList = nil);
- begin
- // nothing
- end;
- procedure TGLFaceGroup.Reverse;
- begin
- // nothing
- end;
- procedure TGLFaceGroup.Prepare;
- begin
- // nothing
- end;
- // ------------------
- // ------------------ TFGVertexIndexList ------------------
- // ------------------
- constructor TFGVertexIndexList.Create;
- begin
- inherited;
- FVertexIndices := TGLIntegerList.Create;
- FMode := fgmmTriangles;
- end;
- destructor TFGVertexIndexList.Destroy;
- begin
- FVertexIndices.Free;
- FIndexVBO.Free;
- inherited;
- end;
- procedure TFGVertexIndexList.WriteToFiler(writer: TGLVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- FVertexIndices.WriteToFiler(writer);
- WriteInteger(Integer(FMode));
- end;
- end;
- procedure TFGVertexIndexList.ReadFromFiler(reader: TGLVirtualReader);
- var
- archiveVersion: Integer;
- begin
- inherited ReadFromFiler(reader);
- archiveVersion := reader.ReadInteger;
- if archiveVersion = 0 then
- with reader do
- begin
- FVertexIndices.ReadFromFiler(reader);
- FMode := TGLFaceGroupMeshMode(ReadInteger);
- InvalidateVBO;
- end
- else
- RaiseFilerException(archiveVersion);
- end;
- procedure TFGVertexIndexList.SetupVBO;
- const
- BufferUsage = GL_STATIC_DRAW;
- begin
- if not Assigned(FIndexVBO) then
- FIndexVBO := TGLVBOElementArrayHandle.Create;
- FIndexVBO.AllocateHandle;
- if FIndexVBO.IsDataNeedUpdate then
- begin
- FIndexVBO.BindBufferData(vertexIndices.list, SizeOf(Integer) * vertexIndices.Count, BufferUsage);
- FIndexVBO.NotifyDataUpdated;
- end;
- end;
- procedure TFGVertexIndexList.SetVertexIndices(const val: TGLIntegerList);
- begin
- FVertexIndices.Assign(val);
- InvalidateVBO;
- end;
- procedure TFGVertexIndexList.BuildList(var mrci: TGLRenderContextInfo);
- const
- cFaceGroupMeshModeToOpenGL: array [TGLFaceGroupMeshMode] 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;
- gl.DrawElements(cFaceGroupMeshModeToOpenGL[mode], vertexIndices.Count, GL_UNSIGNED_INT, nil);
- FIndexVBO.UnBind;
- end
- else
- begin
- gl.DrawElements(cFaceGroupMeshModeToOpenGL[mode], vertexIndices.Count, GL_UNSIGNED_INT, vertexIndices.list);
- end;
- end;
- procedure TFGVertexIndexList.AddToList(Source, destination: TGLAffineVectorList; indices: TGLIntegerList);
- 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 TFGVertexIndexList.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
- aNormals: TGLAffineVectorList = nil);
- var
- mo: TGLMeshObject;
- begin
- mo := Owner.Owner;
- AddToList(mo.Vertices, aList, VertexIndices);
- AddToList(mo.TexCoords, aTexCoords, VertexIndices);
- AddToList(mo.Normals, aNormals, VertexIndices);
- InvalidateVBO;
- end;
- function TFGVertexIndexList.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 TFGVertexIndexList.Reverse;
- begin
- VertexIndices.Reverse;
- InvalidateVBO;
- end;
- procedure TFGVertexIndexList.Add(idx: Integer);
- begin
- FVertexIndices.Add(idx);
- InvalidateVBO;
- end;
- procedure TFGVertexIndexList.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 TFGVertexIndexList.ConvertToList;
- var
- i: Integer;
- bufList: TGLIntegerList;
- begin
- if VertexIndices.Count >= 3 then
- begin
- case Mode of
- fgmmTriangleStrip:
- begin
- bufList := TGLIntegerList.Create;
- try
- ConvertStripToList(VertexIndices, bufList);
- VertexIndices := bufList;
- finally
- bufList.Free;
- end;
- FMode := fgmmTriangles;
- end;
- fgmmTriangleFan:
- begin
- bufList := TGLIntegerList.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 TFGVertexIndexList.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 TFGVertexIndexList.InvalidateVBO;
- begin
- if Assigned(FIndexVBO) then
- FIndexVBO.NotifyChangesOfData;
- end;
- // ------------------
- // ------------------ TFGVertexNormalTexIndexList ------------------
- // ------------------
- constructor TFGVertexNormalTexIndexList.Create;
- begin
- inherited;
- FNormalIndices := TGLIntegerList.Create;
- FTexCoordIndices := TGLIntegerList.Create;
- end;
- destructor TFGVertexNormalTexIndexList.Destroy;
- begin
- FTexCoordIndices.Free;
- FNormalIndices.Free;
- inherited;
- end;
- procedure TFGVertexNormalTexIndexList.WriteToFiler(writer: TGLVirtualWriter);
- 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: TGLVirtualReader);
- 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: TGLIntegerList);
- begin
- FNormalIndices.Assign(val);
- end;
- procedure TFGVertexNormalTexIndexList.SetTexCoordIndices(const val: TGLIntegerList);
- begin
- FTexCoordIndices.Assign(val);
- end;
- procedure TFGVertexNormalTexIndexList.BuildList(var mrci: TGLRenderContextInfo);
- 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: gl.Begin_(GL_TRIANGLES);
- fgmmTriangleStrip: gl.Begin_(GL_TRIANGLE_STRIP);
- fgmmTriangleFan: gl.Begin_(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
- gl.Normal3fv(@normalPool[normalIdxList^[i]]);
- if Assigned(colorPool) then
- gl.Color4fv(@colorPool[vertexIdxList^[i]]);
- if Assigned(texCoordPool) then
- xgl.TexCoord2fv(@texCoordPool[texCoordIdxList^[i]]);
- gl.Vertex3fv(@vertexPool[vertexIdxList^[i]]);
- end;
- gl.End_;
- end;
- procedure TFGVertexNormalTexIndexList.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
- aNormals: TGLAffineVectorList = 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 := TGLAffineVectorList.Create;
- end;
- destructor TFGIndexTexCoordList.Destroy;
- begin
- FTexCoords.Free;
- inherited;
- end;
- procedure TFGIndexTexCoordList.WriteToFiler(writer: TGLVirtualWriter);
- begin
- inherited WriteToFiler(writer);
- with writer do
- begin
- WriteInteger(0); // Archive Version 0
- FTexCoords.WriteToFiler(writer);
- end;
- end;
- procedure TFGIndexTexCoordList.ReadFromFiler(reader: TGLVirtualReader);
- 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: TGLAffineVectorList);
- begin
- FTexCoords.Assign(val);
- end;
- procedure TFGIndexTexCoordList.BuildList(var mrci: TGLRenderContextInfo);
- 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: gl.Begin_(GL_TRIANGLES);
- fgmmFlatTriangles: gl.Begin_(GL_TRIANGLES);
- fgmmTriangleStrip: gl.Begin_(GL_TRIANGLE_STRIP);
- fgmmTriangleFan: gl.Begin_(GL_TRIANGLE_FAN);
- fgmmQuads: gl.Begin_(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
- xgl.TexCoord2fv(@texCoordPool[i]);
- k := indicesPool[i];
- if gotColor then
- gl.Color4fv(@colorPool[k]);
- gl.Normal3fv(@normalPool[k]);
- gl.Vertex3fv(@vertexPool[k]);
- end;
- end
- else
- begin
- for i := 0 to VertexIndices.Count - 1 do
- begin
- xgl.TexCoord2fv(@texCoordPool[i]);
- if gotColor then
- gl.Color4fv(@colorPool[indicesPool[i]]);
- gl.Vertex3fv(@vertexPool[indicesPool[i]]);
- end;
- end;
- gl.End_;
- gl.CheckError;
- end;
- procedure TFGIndexTexCoordList.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
- aNormals: TGLAffineVectorList = nil);
- var
- i, n: Integer;
- texCoordList: TGLAffineVectorList;
- 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;
- // ------------------
- // ------------------ TGLFaceGroups ------------------
- // ------------------
- constructor TGLFaceGroups.CreateOwned(AOwner: TGLMeshObject);
- begin
- FOwner := AOwner;
- Create;
- end;
- destructor TGLFaceGroups.Destroy;
- begin
- Clear;
- inherited;
- end;
- procedure TGLFaceGroups.ReadFromFiler(reader: TGLVirtualReader);
- var
- i: Integer;
- begin
- inherited;
- for i := 0 to Count - 1 do
- Items[i].FOwner := Self;
- end;
- procedure TGLFaceGroups.Clear;
- var
- i: Integer;
- fg: TGLFaceGroup;
- 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 TGLFaceGroups.GetFaceGroup(Index: Integer): TGLFaceGroup;
- begin
- Result := TGLFaceGroup(List^[Index]);
- end;
- procedure TGLFaceGroups.PrepareMaterialLibraryCache(matLib: TGLMaterialLibrary);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TGLFaceGroup(List^[i]).PrepareMaterialLibraryCache(matLib);
- end;
- procedure TGLFaceGroups.DropMaterialLibraryCache;
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- TGLFaceGroup(List^[i]).DropMaterialLibraryCache;
- end;
- procedure TGLFaceGroups.AddToTriangles(aList: TGLAffineVectorList; aTexCoords: TGLAffineVectorList = nil;
- aNormals: TGLAffineVectorList = nil);
- var
- i: Integer;
- begin
- for i := 0 to Count - 1 do
- Items[i].AddToTriangles(aList, aTexCoords, aNormals);
- end;
- function TGLFaceGroups.MaterialLibrary: TGLMaterialLibrary;
- var
- mol: TGLMeshObjectList;
- bm: TGLBaseMesh;
- 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: TGLFaceGroup): Boolean;
- var
- libMat: TGLLibMaterial;
- begin
- libMat := fg.MaterialCache;
- Result := (not Assigned(libMat)) or (not libMat.Material.Blended);
- end;
- var
- fg1, fg2: TGLFaceGroup;
- opaque1, opaque2: Boolean;
- begin
- fg1 := TGLFaceGroup(item1);
- opaque1 := MaterialIsOpaque(fg1);
- fg2 := TGLFaceGroup(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 TGLFaceGroups.SortByMaterial;
- begin
- PrepareMaterialLibraryCache(Owner.Owner.Owner.MaterialLibrary);
- Sort(@CompareMaterials);
- end;
- // ------------------
- // ------------------ TGLVectorFile ------------------
- // ------------------
- constructor TGLVectorFile.Create(AOwner: TPersistent);
- begin
- Assert(AOwner is TGLBaseMesh);
- inherited;
- end;
- function TGLVectorFile.Owner: TGLBaseMesh;
- begin
- Result := TGLBaseMesh(GetOwner);
- end;
- procedure TGLVectorFile.SetNormalsOrientation(const val: TGLMeshNormalsOrientation);
- begin
- FNormalsOrientation := val;
- end;
- // ------------------
- // ------------------ TGLSMVectorFile ------------------
- // ------------------
- class function TGLSMVectorFile.Capabilities: TGLDataFileCapabilities;
- begin
- Result := [dfcRead, dfcWrite];
- end;
- procedure TGLSMVectorFile.LoadFromStream(aStream: TStream);
- begin
- Owner.MeshObjects.LoadFromStream(aStream);
- end;
- procedure TGLSMVectorFile.SaveToStream(aStream: TStream);
- begin
- Owner.MeshObjects.SaveToStream(aStream);
- end;
- // ------------------
- // ------------------ TGLBaseMesh ------------------
- // ------------------
- constructor TGLBaseMesh.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- if FMeshObjects = nil then
- FMeshObjects := TGLMeshObjectList.CreateOwned(Self);
- if FSkeleton = nil then
- FSkeleton := TGLSkeleton.CreateOwned(Self);
- FUseMeshMaterials := True;
- FAutoCentering := [];
- FAxisAlignedDimensionsCache.X := -1;
- FBaryCenterOffsetChanged := True;
- FAutoScaling := TGLCoordinates.CreateInitialized(Self, XYZWHmgVector, csPoint);
- end;
- destructor TGLBaseMesh.Destroy;
- begin
- FConnectivity.Free;
- DropMaterialLibraryCache;
- FSkeleton.Free;
- FMeshObjects.Free;
- FAutoScaling.Free;
- inherited Destroy;
- end;
- procedure TGLBaseMesh.Assign(Source: TPersistent);
- begin
- if Source is TGLBaseMesh then
- begin
- FSkeleton.Clear;
- FNormalsOrientation := TGLBaseMesh(Source).FNormalsOrientation;
- FMaterialLibrary := TGLBaseMesh(Source).FMaterialLibrary;
- FLightmapLibrary := TGLBaseMesh(Source).FLightmapLibrary;
- FAxisAlignedDimensionsCache := TGLBaseMesh(Source).FAxisAlignedDimensionsCache;
- FBaryCenterOffset := TGLBaseMesh(Source).FBaryCenterOffset;
- FUseMeshMaterials := TGLBaseMesh(Source).FUseMeshMaterials;
- FOverlaySkeleton := TGLBaseMesh(Source).FOverlaySkeleton;
- FIgnoreMissingTextures := TGLBaseMesh(Source).FIgnoreMissingTextures;
- FAutoCentering := TGLBaseMesh(Source).FAutoCentering;
- FAutoScaling.Assign(TGLBaseMesh(Source).FAutoScaling);
- FSkeleton.Assign(TGLBaseMesh(Source).FSkeleton);
- FSkeleton.RootBones.PrepareGlobalMatrices;
- FMeshObjects.Assign(TGLBaseMesh(Source).FMeshObjects);
- end;
- inherited Assign(Source);
- end;
- procedure TGLBaseMesh.LoadFromFile(const filename: string);
- var
- fs: TFileStream;
- begin
- FLastLoadedFilename := '';
- if fileName <> '' then
- begin
- try
- fs := TFileStream.Create(fileName, fmOpenRead + fmShareDenyWrite);
- LoadFromStream(fileName, fs);
- FLastLoadedFilename := filename;
- finally
- fs.Free;
- end;
- end;
- end;
- procedure TGLBaseMesh.LoadFromStream(const fileName: string; aStream: TStream);
- var
- newVectorFile: TGLVectorFile;
- vectorFileClass: TGLVectorFileClass;
- 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 TGLBaseMesh.SaveToFile(const filename: string);
- var
- fs: TStream;
- begin
- if fileName <> '' then
- begin
- try
- fs := TFileStream.Create(fileName, fmCreate);
- SaveToStream(fileName, fs);
- finally
- fs.Free;
- end;
- end;
- end;
- procedure TGLBaseMesh.SaveToStream(const fileName: string; aStream: TStream);
- var
- newVectorFile: TGLVectorFile;
- vectorFileClass: TGLVectorFileClass;
- 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 TGLBaseMesh.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 TGLBaseMesh.AddDataFromStream(const filename: string; aStream: TStream);
- var
- newVectorFile: TGLVectorFile;
- VectorFileClass: TGLVectorFileClass;
- 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 TGLBaseMesh.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
- TGLMeshObject(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 TGLBaseMesh.GetBarycenter: TAffineVector;
- var
- i, nb: Integer;
- begin
- Result := NullVector;
- nb := 0;
- for i := 0 to MeshObjects.Count - 1 do
- TGLMeshObject(MeshObjects[i]).ContributeToBarycenter(Result, nb);
- if nb > 0 then
- ScaleVector(Result, 1 / nb);
- end;
- function TGLBaseMesh.LastLoadedFilename: string;
- begin
- Result := FLastLoadedFilename;
- end;
- procedure TGLBaseMesh.SetMaterialLibrary(const val: TGLMaterialLibrary);
- 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 TGLBaseMesh.SetLightmapLibrary(const val: TGLMaterialLibrary);
- 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 TGLBaseMesh.SetNormalsOrientation(const val: TGLMeshNormalsOrientation);
- begin
- if val <> FNormalsOrientation then
- begin
- FNormalsOrientation := val;
- StructureChanged;
- end;
- end;
- procedure TGLBaseMesh.SetOverlaySkeleton(const val: Boolean);
- begin
- if FOverlaySkeleton <> val then
- begin
- FOverlaySkeleton := val;
- NotifyChange(Self);
- end;
- end;
- procedure TGLBaseMesh.SetAutoScaling(const Value: TGLCoordinates);
- begin
- FAutoScaling.SetPoint(Value.DirectX, Value.DirectY, Value.DirectZ);
- end;
- procedure TGLBaseMesh.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 TGLBaseMesh.AxisAlignedDimensionsUnscaled: TGLVector;
- 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 TGLBaseMesh.BarycenterOffset: TGLVector;
- 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 TGLBaseMesh.BarycenterPosition: TGLVector;
- begin
- Result := VectorAdd(Position.DirectVector, BarycenterOffset);
- end;
- function TGLBaseMesh.BarycenterAbsolutePosition: TGLVector;
- begin
- Result := LocalToAbsolute(BarycenterPosition);
- end;
- procedure TGLBaseMesh.DestroyHandle;
- begin
- if Assigned(FMaterialLibrary) then
- MaterialLibrary.DestroyHandles;
- if Assigned(FLightmapLibrary) then
- LightmapLibrary.DestroyHandles;
- inherited;
- end;
- procedure TGLBaseMesh.PrepareVectorFile(aFile: TGLVectorFile);
- begin
- aFile.NormalsOrientation := NormalsOrientation;
- end;
- procedure TGLBaseMesh.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 TGLBaseMesh.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 TGLBaseMesh.PrepareMesh;
- begin
- StructureChanged;
- end;
- procedure TGLBaseMesh.PrepareMaterialLibraryCache;
- begin
- if FMaterialLibraryCachesPrepared then
- DropMaterialLibraryCache;
- MeshObjects.PrepareMaterialLibraryCache(FMaterialLibrary);
- FMaterialLibraryCachesPrepared := True;
- end;
- procedure TGLBaseMesh.DropMaterialLibraryCache;
- begin
- if FMaterialLibraryCachesPrepared then
- begin
- MeshObjects.DropMaterialLibraryCache;
- FMaterialLibraryCachesPrepared := False;
- end;
- end;
- procedure TGLBaseMesh.PrepareBuildList(var mrci: TGLRenderContextInfo);
- begin
- MeshObjects.PrepareBuildList(mrci);
- if LightmapLibrary <> nil then
- LightmapLibrary.Materials.PrepareBuildList
- end;
- procedure TGLBaseMesh.SetUseMeshMaterials(const val: Boolean);
- begin
- if val <> FUseMeshMaterials then
- begin
- FUseMeshMaterials := val;
- if FMaterialLibraryCachesPrepared and (not val) then
- DropMaterialLibraryCache;
- StructureChanged;
- end;
- end;
- procedure TGLBaseMesh.BuildList(var rci: TGLRenderContextInfo);
- begin
- MeshObjects.BuildList(rci);
- end;
- procedure TGLBaseMesh.DoRender(var rci: TGLRenderContextInfo; renderSelf, renderChildren: Boolean);
- begin
- if Assigned(LightmapLibrary) then
- xgl.ForbidSecondTextureUnit;
- if renderSelf then
- begin
- // set winding
- case FNormalsOrientation of
- mnoDefault: ; // nothing
- mnoInvert: rci.GLStates.InvertGLFrontFace;
- 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.GLStates.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.GLStates.CallList(GetHandle(rci));
- end;
- if FNormalsOrientation <> mnoDefault then
- rci.GLStates.InvertGLFrontFace;
- end;
- if Assigned(LightmapLibrary) then
- xgl.AllowSecondTextureUnit;
- if renderChildren and (Count > 0) then
- Self.RenderChildren(0, Count - 1, rci);
- end;
- procedure TGLBaseMesh.StructureChanged;
- begin
- FAxisAlignedDimensionsCache.X := -1;
- FBaryCenterOffsetChanged := True;
- DropMaterialLibraryCache;
- MeshObjects.Prepare;
- inherited;
- end;
- procedure TGLBaseMesh.StructureChangedNoPrepare;
- begin
- inherited StructureChanged;
- end;
- function TGLBaseMesh.RayCastIntersect(const rayStart, rayVector: TGLVector; intersectPoint: PGLVector = nil;
- intersectNormal: PGLVector = nil): Boolean;
- var
- i,j: Integer;
- Obj: TGLMeshObject;
- Tris: TGLAffineVectorList;
- locRayStart, locRayVector, iPoint, iNormal: TGLVector;
- d, minD: Single;
- begin
- SetVector(locRayStart, AbsoluteToLocal(rayStart));
- SetVector(locRayVector, AbsoluteToLocal(rayVector));
- minD := -1;
- for j := 0 to MeshObjects.Count - 1 do
- begin
- Obj := MeshObjects.GetMeshObject(j);
- if not Obj.Visible then
- Continue;
- Tris := Obj.ExtractTriangles(NIL, NIL); //objTexCoords & objNormals
- try
- 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;
- 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 TGLBaseMesh.GenerateSilhouette(const silhouetteParameters: TGLSilhouetteParameters): TGLSilhouette;
- var
- mc: TGLBaseMeshConnectivity;
- sil: TGLSilhouette;
- begin
- sil := nil;
- if Assigned(FConnectivity) then
- begin
- mc := TGLBaseMeshConnectivity(FConnectivity);
- mc.CreateSilhouette(silhouetteParameters, sil, True);
- end
- else
- begin
- mc := TGLBaseMeshConnectivity.CreateFromMesh(Self);
- try
- mc.CreateSilhouette(silhouetteParameters, sil, True);
- finally
- mc.Free;
- end;
- end;
- Result := sil;
- end;
- procedure TGLBaseMesh.BuildSilhouetteConnectivityData;
- var
- i, j: Integer;
- mo: TGLMeshObject;
- begin
- FreeAndNil(FConnectivity);
- // connectivity data works only on facegroups of TFGVertexIndexList class
- for i := 0 to MeshObjects.Count - 1 do
- begin
- mo := (MeshObjects[i] as TGLMeshObject);
- if mo.Mode <> momFaceGroups then
- Exit;
- for j := 0 to mo.FaceGroups.Count - 1 do
- if not mo.FaceGroups[j].InheritsFrom(TFGVertexIndexList) then
- Exit;
- end;
- FConnectivity := TGLBaseMeshConnectivity.CreateFromMesh(Self);
- end;
- // ------------------
- // ------------------ TGLFreeForm ------------------
- // ------------------
- constructor TGLFreeForm.Create(aOwner: TComponent);
- begin
- inherited;
- // ObjectStyle := [osDirectDraw];
- FUseMeshMaterials := True;
- end;
- destructor TGLFreeForm.Destroy;
- begin
- FOctree.Free;
- inherited Destroy;
- end;
- procedure TGLFreeForm.BuildOctree(TreeDepth: Integer = 3);
- var
- emin, emax: TAffineVector;
- tl: TGLAffineVectorList;
- begin
- if not Assigned(FOctree) then // moved here from GetOctree
- FOctree := TGLOctree.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 TGLFreeForm.OctreeRayCastIntersect(const rayStart, rayVector: TGLVector; intersectPoint: PGLVector = nil;
- intersectNormal: PGLVector = nil): Boolean;
- var
- locRayStart, locRayVector: TGLVector;
- begin
- Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
- 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 TGLFreeForm.OctreePointInMesh(const Point: TGLVector): Boolean;
- const
- cPointRadiusStep = 10000;
- var
- rayStart, rayVector, hitPoint, hitNormal: TGLVector;
- BRad: double;
- HitCount: Integer;
- hitDot: double;
- begin
- Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
- 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 TGLFreeForm.OctreeSphereSweepIntersect(const rayStart, rayVector: TGLVector; const velocity, radius: Single;
- intersectPoint: PGLVector = nil; intersectNormal: PGLVector = nil): Boolean;
- var
- locRayStart, locRayVector: TGLVector;
- begin
- Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
- 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 TGLFreeForm.OctreeTriangleIntersect(const v1, v2, v3: TAffineVector): Boolean;
- var
- t1, t2, t3: TAffineVector;
- begin
- Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
- SetVector(t1, AbsoluteToLocal(v1));
- SetVector(t2, AbsoluteToLocal(v2));
- SetVector(t3, AbsoluteToLocal(v3));
- Result := Octree.TriangleIntersect(t1, t2, t3);
- end;
- function TGLFreeForm.OctreeAABBIntersect(const AABB: TAABB; objMatrix, invObjMatrix: TGLMatrix;
- triangles: TGLAffineVectorList = nil): Boolean;
- var
- m1to2, m2to1: TGLMatrix;
- begin
- Assert(Assigned(FOctree), strOctreeMustBePreparedBeforeUse);
- // 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;
- // ------------------
- // ------------------ TGLActorAnimation ------------------
- // ------------------
- constructor TGLActorAnimation.Create(Collection: TCollection);
- begin
- inherited Create(Collection);
- end;
- destructor TGLActorAnimation.Destroy;
- begin
- with (Collection as TGLActorAnimations).FOwner do
- if FTargetSmoothAnimation = Self then
- FTargetSmoothAnimation := nil;
- inherited Destroy;
- end;
- procedure TGLActorAnimation.Assign(Source: TPersistent);
- begin
- if Source is TGLActorAnimation then
- begin
- FName := TGLActorAnimation(Source).FName;
- FStartFrame := TGLActorAnimation(Source).FStartFrame;
- FEndFrame := TGLActorAnimation(Source).FEndFrame;
- FReference := TGLActorAnimation(Source).FReference;
- end
- else
- inherited;
- end;
- function TGLActorAnimation.GetDisplayName: string;
- begin
- Result := Format('%d - %s [%d - %d]', [Index, Name, StartFrame, EndFrame]);
- end;
- function TGLActorAnimation.FrameCount: Integer;
- begin
- case Reference of
- aarMorph: Result := TGLActorAnimations(Collection).FOwner.MeshObjects.MorphTargetCount;
- aarSkeleton: Result := TGLActorAnimations(Collection).FOwner.Skeleton.Frames.Count;
- else
- Result := 0;
- Assert(False);
- end;
- end;
- procedure TGLActorAnimation.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 TGLActorAnimation.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 TGLActorAnimation.SetReference(val: TGLActorAnimationReference);
- begin
- if val <> FReference then
- begin
- FReference := val;
- StartFrame := StartFrame;
- EndFrame := EndFrame;
- end;
- end;
- procedure TGLActorAnimation.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 TGLActorAnimation.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 TGLActorAnimation.OwnerActor: TGLActor;
- begin
- Result := ((Collection as TGLActorAnimations).GetOwner as TGLActor);
- end;
- procedure TGLActorAnimation.MakeSkeletalTranslationStatic;
- begin
- OwnerActor.Skeleton.MakeSkeletalTranslationStatic(StartFrame, EndFrame);
- end;
- procedure TGLActorAnimation.MakeSkeletalRotationDelta;
- begin
- OwnerActor.Skeleton.MakeSkeletalRotationDelta(StartFrame, EndFrame);
- end;
- // ------------------
- // ------------------ TGLActorAnimations ------------------
- // ------------------
- constructor TGLActorAnimations.Create(AOwner: TGLActor);
- begin
- FOwner := AOwner;
- inherited Create(TGLActorAnimation);
- end;
- function TGLActorAnimations.GetOwner: TPersistent;
- begin
- Result := FOwner;
- end;
- procedure TGLActorAnimations.SetItems(Index: Integer; const val: TGLActorAnimation);
- begin
- inherited Items[index] := val;
- end;
- function TGLActorAnimations.GetItems(Index: Integer): TGLActorAnimation;
- begin
- Result := TGLActorAnimation(inherited Items[index]);
- end;
- function TGLActorAnimations.Last: TGLActorAnimation;
- begin
- if Count > 0 then
- Result := TGLActorAnimation(inherited Items[Count - 1])
- else
- Result := nil;
- end;
- function TGLActorAnimations.Add: TGLActorAnimation;
- begin
- Result := (inherited Add) as TGLActorAnimation;
- end;
- function TGLActorAnimations.FindItemID(ID: Integer): TGLActorAnimation;
- begin
- Result := (inherited FindItemID(ID)) as TGLActorAnimation;
- end;
- function TGLActorAnimations.FindName(const aName: string): TGLActorAnimation;
- 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 TGLActorAnimations.FindFrame(aFrame: Integer; aReference: TGLActorAnimationReference): TGLActorAnimation;
- 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 TGLActorAnimations.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 TGLActorAnimations.SaveToStream(aStream: TStream);
- var
- i: Integer;
- begin
- WriteCRLFString(aStream, cAAFHeader);
- WriteCRLFString(aStream, IntToStr(Count));
- for i := 0 to Count - 1 do
- WriteCRLFString(aStream, Items[i].AsString);
- end;
- procedure TGLActorAnimations.LoadFromStream(aStream: TStream);
- var
- i, n: Integer;
- begin
- Clear;
- if ReadCRLFString(aStream) <> cAAFHeader then
- Assert(False);
- n := StrToInt(ReadCRLFString(aStream));
- for i := 0 to n - 1 do
- Add.AsString := ReadCRLFString(aStream);
- end;
- procedure TGLActorAnimations.SaveToFile(const fileName: string);
- var
- fs: TStream;
- begin
- fs := TFileStream.Create(fileName, fmCreate);
- try
- SaveToStream(fs);
- finally
- fs.Free;
- end;
- end;
- procedure TGLActorAnimations.LoadFromFile(const fileName: string);
- var
- fs: TStream;
- begin
- try
- fs := TFileStream.Create(fileName, fmOpenRead + fmShareDenyWrite);
- finally
- fs.Free;
- end;
- end;
- // ------------------
- // ------------------ TGLBaseAnimationControler ------------------
- // ------------------
- constructor TGLBaseAnimationControler.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- FEnabled := True;
- end;
- destructor TGLBaseAnimationControler.Destroy;
- begin
- SetActor(nil);
- inherited Destroy;
- end;
- procedure TGLBaseAnimationControler.Notification(AComponent: TComponent; Operation: TOperation);
- begin
- if (AComponent = FActor) and (Operation = opRemove) then
- SetActor(nil);
- inherited;
- end;
- procedure TGLBaseAnimationControler.DoChange;
- begin
- if Assigned(FActor) then
- FActor.NotifyChange(Self);
- end;
- procedure TGLBaseAnimationControler.SetEnabled(const val: Boolean);
- begin
- if val <> FEnabled then
- begin
- FEnabled := val;
- if Assigned(FActor) then
- DoChange;
- end;
- end;
- procedure TGLBaseAnimationControler.SetActor(const val: TGLActor);
- 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 TGLBaseAnimationControler.Apply(var lerpInfo: TGLBlendedLerpInfo): Boolean;
- begin
- // virtual
- Result := False;
- end;
- // ------------------
- // ------------------ TGLAnimationControler ------------------
- // ------------------
- procedure TGLAnimationControler.DoChange;
- begin
- if AnimationName <> '' then
- inherited;
- end;
- procedure TGLAnimationControler.SetAnimationName(const val: TGLActorAnimationName);
- begin
- if FAnimationName <> val then
- begin
- FAnimationName := val;
- DoChange;
- end;
- end;
- procedure TGLAnimationControler.SetRatio(const val: Single);
- begin
- if FRatio <> val then
- begin
- FRatio := ClampValue(val, 0, 1);
- DoChange;
- end;
- end;
- function TGLAnimationControler.Apply(var lerpInfo: TGLBlendedLerpInfo): Boolean;
- var
- anim: TGLActorAnimation;
- 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;
- // ------------------
- // ------------------ TGLActor ------------------
- // ------------------
- constructor TGLActor.Create(AOwner: TComponent);
- begin
- inherited Create(AOwner);
- ObjectStyle := ObjectStyle + [osDirectDraw];
- FFrameInterpolation := afpLinear;
- FAnimationMode := aamNone;
- FInterval := 100; // 10 animation frames per second
- FAnimations := TGLActorAnimations.Create(Self);
- FControlers := nil; // created on request
- FOptions := cDefaultActorOptions;
- end;
- destructor TGLActor.Destroy;
- begin
- inherited Destroy;
- FControlers.Free;
- FAnimations.Free;
- end;
- procedure TGLActor.Assign(Source: TPersistent);
- begin
- inherited Assign(Source);
- if Source is TGLActor then
- begin
- FAnimations.Assign(TGLActor(Source).FAnimations);
- FAnimationMode := TGLActor(Source).FAnimationMode;
- Synchronize(TGLActor(Source));
- end;
- end;
- procedure TGLActor.RegisterControler(aControler: TGLBaseAnimationControler);
- begin
- if not Assigned(FControlers) then
- FControlers := TList.Create;
- FControlers.Add(aControler);
- FreeNotification(aControler);
- end;
- procedure TGLActor.UnRegisterControler(aControler: TGLBaseAnimationControler);
- begin
- Assert(Assigned(FControlers));
- FControlers.Remove(aControler);
- RemoveFreeNotification(aControler);
- if FControlers.Count = 0 then
- FreeAndNil(FControlers);
- end;
- procedure TGLActor.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 TGLActor.SetCurrentFrameDirect(const Value: Integer);
- begin
- FCurrentFrame := Value;
- end;
- procedure TGLActor.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 TGLActor.SetEndFrame(val: Integer);
- begin
- if (val >= 0) and (val < FrameCount) and (val <> EndFrame) then
- FEndFrame := val;
- if CurrentFrame > EndFrame then
- CurrentFrame := FEndFrame;
- end;
- procedure TGLActor.SetReference(val: TGLActorAnimationReference);
- begin
- if val <> Reference then
- begin
- FReference := val;
- StartFrame := StartFrame;
- EndFrame := EndFrame;
- CurrentFrame := CurrentFrame;
- StructureChanged;
- end;
- end;
- procedure TGLActor.SetAnimations(const val: TGLActorAnimations);
- begin
- FAnimations.Assign(val);
- end;
- function TGLActor.StoreAnimations: Boolean;
- begin
- Result := (FAnimations.Count > 0);
- end;
- procedure TGLActor.SetOptions(const val: TGLActorOptions);
- begin
- if val <> FOptions then
- begin
- FOptions := val;
- StructureChanged;
- end;
- end;
- function TGLActor.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 TGLActor.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 TGLActor.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 TGLActor.DoAnimate();
- var
- i, k: Integer;
- nextFrameIdx: Integer;
- lerpInfos: array of TGLBlendedLerpInfo;
- 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 TGLBaseAnimationControler(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 TGLActor.BuildList(var rci: TGLRenderContextInfo);
- begin
- DoAnimate;
- inherited;
- if OverlaySkeleton then
- begin
- rci.GLStates.Disable(stDepthTest);
- Skeleton.RootBones.BuildList(rci);
- end;
- end;
- procedure TGLActor.PrepareMesh;
- begin
- FStartFrame := 0;
- FEndFrame := FrameCount - 1;
- FCurrentFrame := 0;
- if Assigned(FOnFrameChanged) then
- FOnFrameChanged(Self);
- inherited;
- end;
- procedure TGLActor.PrepareBuildList(var mrci: TGLRenderContextInfo);
- begin
- // no preparation needed for actors, they don't use buildlists
- end;
- function TGLActor.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 TGLActor.DoProgress(const progressTime: TGLProgressTimes);
- 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 TGLActor.LoadFromStream(const FileName: string; aStream: TStream);
- begin
- if FileName <> '' then
- begin
- Animations.Clear;
- inherited LoadFromStream(FileName, aStream);
- end;
- end;
- procedure TGLActor.SwitchToAnimation(const AnimationName: string; smooth: Boolean = False);
- begin
- SwitchToAnimation(Animations.FindName(AnimationName), smooth);
- end;
- procedure TGLActor.SwitchToAnimation(animationIndex: Integer; smooth: Boolean = False);
- begin
- if (animationIndex >= 0) and (animationIndex < Animations.Count) then
- SwitchToAnimation(Animations[animationIndex], smooth);
- end;
- procedure TGLActor.SwitchToAnimation(anAnimation: TGLActorAnimation; 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 TGLActor.CurrentAnimation: string;
- var
- aa: TGLActorAnimation;
- begin
- aa := Animations.FindFrame(CurrentFrame, Reference);
- if Assigned(aa) then
- Result := aa.Name
- else
- Result := '';
- end;
- procedure TGLActor.Synchronize(referenceActor: TGLActor);
- 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 TGLActor.isSwitchingAnimation: boolean;
- begin
- result := FTargetSmoothAnimation <> nil;
- end;
- // ------------------------------------------------------------------
- initialization
- // ------------------------------------------------------------------
- RegisterVectorFileFormat('glsm', 'GLScene Mesh', TGLSMVectorFile);
- RegisterClasses(
- [TGLFreeForm, TGLActor, TGLSkeleton, TGLSkeletonFrame, TGLSkeletonBone,
- TGLSkeletonMeshObject, TGLMeshObject, TGLSkeletonFrameList, TGLMeshMorphTarget,
- TGLMorphableMeshObject, TGLFaceGroup, TFGVertexIndexList,
- TFGVertexNormalTexIndexList, TGLAnimationControler,
- TFGIndexTexCoordList, TGLSkeletonCollider, TGLSkeletonColliderList]);
- finalization
- FreeAndNil(vVectorFileFormats);
- end.
|