1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546 |
- //
- // The graphics engine GLScene
- //
- unit GLS.VectorFileObjects;
- (*
- Vector File related objects.
- The registered classes are:
- [TGLFreeForm, TGLActor, TGLSkeleton, TGLSkeletonFrame, TGLSkeletonBone,
- TGLSkeletonMeshObject, TGLMeshObject, TGLSkeletonFrameList, TGLMeshMorphTarget,
- TGLMorphableMeshObject, TGLFaceGroup, TFGVertexIndexList,
- TFGVertexNormalTexIndexList, TGLAnimationControler,
- TFGIndexTexCoordList, TGLSkeletonCollider, TGLSkeletonColliderList
- TGLBaseMeshObject, TGLSkeleton, TGLMeshObject, TGLSkeletonMeshObject;
- TGLFaceGroup, TGLVectorFile, TGLSMVectorFile, TGLFreeForm;
- TGLActor, TGLVectorFileFormat, TGLVectorFileFormatsList]
- *)
- interface
- {$I Stage.Defines.inc}
- uses
- Winapi.OpenGL,
- Winapi.OpenGLext,
- System.Classes,
- System.SysUtils,
- System.Types,
- System.Math,
- VCL.Consts,
- Stage.OpenGLTokens,
- Stage.VectorTypes,
- Stage.VectorTypesExt,
- Stage.TextureFormat,
- Stage.VectorGeometry,
- GLS.VectorLists,
- GLS.PersistentClasses,
- GLS.Coordinates,
- GLS.BaseClasses,
- GLS.GeometryBB,
- Stage.Utils,
- GLS.Scene,
- GLS.Silhouette,
- Stage.Strings,
- GLS.Texture,
- GLS.Material,
- GLS.Mesh,
- GLS.Octree,
- GLS.ApplicationFileIO,
- GLS.Context,
- GLS.Color,
- Stage.PipelineTransform,
- GLS.Selection,
- GLS.XOpenGL,
- GLS.MeshUtils,
- GLS.State,
- GLS.RenderContextInfo;
- 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.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
- fs := TBufferedFileStream.Create(fileName, fmOpenRead + fmShareDenyWrite);
- try
- 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
- fs := TFileStream.Create(fileName, fmCreate);
- try
- 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.InvertFrontFace;
- else
- Assert(False);
- end;
- if not rci.ignoreMaterials then
- begin
- if UseMeshMaterials and Assigned(MaterialLibrary) then
- begin
- rci.MaterialLibrary := MaterialLibrary;
- if not FMaterialLibraryCachesPrepared then
- PrepareMaterialLibraryCache;
- end
- else
- rci.MaterialLibrary := nil;
- if Assigned(LightmapLibrary) then
- rci.LightmapLibrary := LightmapLibrary
- else
- rci.LightmapLibrary := nil;
- if rci.amalgamating or not(ListHandleAllocated or (osDirectDraw in ObjectStyle)) then
- PrepareBuildList(rci);
- Material.Apply(rci);
- repeat
- if (osDirectDraw in ObjectStyle) or
- rci.amalgamating or UseMeshMaterials then
- BuildList(rci)
- else
- rci.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.InvertFrontFace;
- 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.
|