ufbx.c 1.1 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348183491835018351183521835318354183551835618357183581835918360183611836218363183641836518366183671836818369183701837118372183731837418375183761837718378183791838018381183821838318384183851838618387183881838918390183911839218393183941839518396183971839818399184001840118402184031840418405184061840718408184091841018411184121841318414184151841618417184181841918420184211842218423184241842518426184271842818429184301843118432184331843418435184361843718438184391844018441184421844318444184451844618447184481844918450184511845218453184541845518456184571845818459184601846118462184631846418465184661846718468184691847018471184721847318474184751847618477184781847918480184811848218483184841848518486184871848818489184901849118492184931849418495184961849718498184991850018501185021850318504185051850618507185081850918510185111851218513185141851518516185171851818519185201852118522185231852418525185261852718528185291853018531185321853318534185351853618537185381853918540185411854218543185441854518546185471854818549185501855118552185531855418555185561855718558185591856018561185621856318564185651856618567185681856918570185711857218573185741857518576185771857818579185801858118582185831858418585185861858718588185891859018591185921859318594185951859618597185981859918600186011860218603186041860518606186071860818609186101861118612186131861418615186161861718618186191862018621186221862318624186251862618627186281862918630186311863218633186341863518636186371863818639186401864118642186431864418645186461864718648186491865018651186521865318654186551865618657186581865918660186611866218663186641866518666186671866818669186701867118672186731867418675186761867718678186791868018681186821868318684186851868618687186881868918690186911869218693186941869518696186971869818699187001870118702187031870418705187061870718708187091871018711187121871318714187151871618717187181871918720187211872218723187241872518726187271872818729187301873118732187331873418735187361873718738187391874018741187421874318744187451874618747187481874918750187511875218753187541875518756187571875818759187601876118762187631876418765187661876718768187691877018771187721877318774187751877618777187781877918780187811878218783187841878518786187871878818789187901879118792187931879418795187961879718798187991880018801188021880318804188051880618807188081880918810188111881218813188141881518816188171881818819188201882118822188231882418825188261882718828188291883018831188321883318834188351883618837188381883918840188411884218843188441884518846188471884818849188501885118852188531885418855188561885718858188591886018861188621886318864188651886618867188681886918870188711887218873188741887518876188771887818879188801888118882188831888418885188861888718888188891889018891188921889318894188951889618897188981889918900189011890218903189041890518906189071890818909189101891118912189131891418915189161891718918189191892018921189221892318924189251892618927189281892918930189311893218933189341893518936189371893818939189401894118942189431894418945189461894718948189491895018951189521895318954189551895618957189581895918960189611896218963189641896518966189671896818969189701897118972189731897418975189761897718978189791898018981189821898318984189851898618987189881898918990189911899218993189941899518996189971899818999190001900119002190031900419005190061900719008190091901019011190121901319014190151901619017190181901919020190211902219023190241902519026190271902819029190301903119032190331903419035190361903719038190391904019041190421904319044190451904619047190481904919050190511905219053190541905519056190571905819059190601906119062190631906419065190661906719068190691907019071190721907319074190751907619077190781907919080190811908219083190841908519086190871908819089190901909119092190931909419095190961909719098190991910019101191021910319104191051910619107191081910919110191111911219113191141911519116191171911819119191201912119122191231912419125191261912719128191291913019131191321913319134191351913619137191381913919140191411914219143191441914519146191471914819149191501915119152191531915419155191561915719158191591916019161191621916319164191651916619167191681916919170191711917219173191741917519176191771917819179191801918119182191831918419185191861918719188191891919019191191921919319194191951919619197191981919919200192011920219203192041920519206192071920819209192101921119212192131921419215192161921719218192191922019221192221922319224192251922619227192281922919230192311923219233192341923519236192371923819239192401924119242192431924419245192461924719248192491925019251192521925319254192551925619257192581925919260192611926219263192641926519266192671926819269192701927119272192731927419275192761927719278192791928019281192821928319284192851928619287192881928919290192911929219293192941929519296192971929819299193001930119302193031930419305193061930719308193091931019311193121931319314193151931619317193181931919320193211932219323193241932519326193271932819329193301933119332193331933419335193361933719338193391934019341193421934319344193451934619347193481934919350193511935219353193541935519356193571935819359193601936119362193631936419365193661936719368193691937019371193721937319374193751937619377193781937919380193811938219383193841938519386193871938819389193901939119392193931939419395193961939719398193991940019401194021940319404194051940619407194081940919410194111941219413194141941519416194171941819419194201942119422194231942419425194261942719428194291943019431194321943319434194351943619437194381943919440194411944219443194441944519446194471944819449194501945119452194531945419455194561945719458194591946019461194621946319464194651946619467194681946919470194711947219473194741947519476194771947819479194801948119482194831948419485194861948719488194891949019491194921949319494194951949619497194981949919500195011950219503195041950519506195071950819509195101951119512195131951419515195161951719518195191952019521195221952319524195251952619527195281952919530195311953219533195341953519536195371953819539195401954119542195431954419545195461954719548195491955019551195521955319554195551955619557195581955919560195611956219563195641956519566195671956819569195701957119572195731957419575195761957719578195791958019581195821958319584195851958619587195881958919590195911959219593195941959519596195971959819599196001960119602196031960419605196061960719608196091961019611196121961319614196151961619617196181961919620196211962219623196241962519626196271962819629196301963119632196331963419635196361963719638196391964019641196421964319644196451964619647196481964919650196511965219653196541965519656196571965819659196601966119662196631966419665196661966719668196691967019671196721967319674196751967619677196781967919680196811968219683196841968519686196871968819689196901969119692196931969419695196961969719698196991970019701197021970319704197051970619707197081970919710197111971219713197141971519716197171971819719197201972119722197231972419725197261972719728197291973019731197321973319734197351973619737197381973919740197411974219743197441974519746197471974819749197501975119752197531975419755197561975719758197591976019761197621976319764197651976619767197681976919770197711977219773197741977519776197771977819779197801978119782197831978419785197861978719788197891979019791197921979319794197951979619797197981979919800198011980219803198041980519806198071980819809198101981119812198131981419815198161981719818198191982019821198221982319824198251982619827198281982919830198311983219833198341983519836198371983819839198401984119842198431984419845198461984719848198491985019851198521985319854198551985619857198581985919860198611986219863198641986519866198671986819869198701987119872198731987419875198761987719878198791988019881198821988319884198851988619887198881988919890198911989219893198941989519896198971989819899199001990119902199031990419905199061990719908199091991019911199121991319914199151991619917199181991919920199211992219923199241992519926199271992819929199301993119932199331993419935199361993719938199391994019941199421994319944199451994619947199481994919950199511995219953199541995519956199571995819959199601996119962199631996419965199661996719968199691997019971199721997319974199751997619977199781997919980199811998219983199841998519986199871998819989199901999119992199931999419995199961999719998199992000020001200022000320004200052000620007200082000920010200112001220013200142001520016200172001820019200202002120022200232002420025200262002720028200292003020031200322003320034200352003620037200382003920040200412004220043200442004520046200472004820049200502005120052200532005420055200562005720058200592006020061200622006320064200652006620067200682006920070200712007220073200742007520076200772007820079200802008120082200832008420085200862008720088200892009020091200922009320094200952009620097200982009920100201012010220103201042010520106201072010820109201102011120112201132011420115201162011720118201192012020121201222012320124201252012620127201282012920130201312013220133201342013520136201372013820139201402014120142201432014420145201462014720148201492015020151201522015320154201552015620157201582015920160201612016220163201642016520166201672016820169201702017120172201732017420175201762017720178201792018020181201822018320184201852018620187201882018920190201912019220193201942019520196201972019820199202002020120202202032020420205202062020720208202092021020211202122021320214202152021620217202182021920220202212022220223202242022520226202272022820229202302023120232202332023420235202362023720238202392024020241202422024320244202452024620247202482024920250202512025220253202542025520256202572025820259202602026120262202632026420265202662026720268202692027020271202722027320274202752027620277202782027920280202812028220283202842028520286202872028820289202902029120292202932029420295202962029720298202992030020301203022030320304203052030620307203082030920310203112031220313203142031520316203172031820319203202032120322203232032420325203262032720328203292033020331203322033320334203352033620337203382033920340203412034220343203442034520346203472034820349203502035120352203532035420355203562035720358203592036020361203622036320364203652036620367203682036920370203712037220373203742037520376203772037820379203802038120382203832038420385203862038720388203892039020391203922039320394203952039620397203982039920400204012040220403204042040520406204072040820409204102041120412204132041420415204162041720418204192042020421204222042320424204252042620427204282042920430204312043220433204342043520436204372043820439204402044120442204432044420445204462044720448204492045020451204522045320454204552045620457204582045920460204612046220463204642046520466204672046820469204702047120472204732047420475204762047720478204792048020481204822048320484204852048620487204882048920490204912049220493204942049520496204972049820499205002050120502205032050420505205062050720508205092051020511205122051320514205152051620517205182051920520205212052220523205242052520526205272052820529205302053120532205332053420535205362053720538205392054020541205422054320544205452054620547205482054920550205512055220553205542055520556205572055820559205602056120562205632056420565205662056720568205692057020571205722057320574205752057620577205782057920580205812058220583205842058520586205872058820589205902059120592205932059420595205962059720598205992060020601206022060320604206052060620607206082060920610206112061220613206142061520616206172061820619206202062120622206232062420625206262062720628206292063020631206322063320634206352063620637206382063920640206412064220643206442064520646206472064820649206502065120652206532065420655206562065720658206592066020661206622066320664206652066620667206682066920670206712067220673206742067520676206772067820679206802068120682206832068420685206862068720688206892069020691206922069320694206952069620697206982069920700207012070220703207042070520706207072070820709207102071120712207132071420715207162071720718207192072020721207222072320724207252072620727207282072920730207312073220733207342073520736207372073820739207402074120742207432074420745207462074720748207492075020751207522075320754207552075620757207582075920760207612076220763207642076520766207672076820769207702077120772207732077420775207762077720778207792078020781207822078320784207852078620787207882078920790207912079220793207942079520796207972079820799208002080120802208032080420805208062080720808208092081020811208122081320814208152081620817208182081920820208212082220823208242082520826208272082820829208302083120832208332083420835208362083720838208392084020841208422084320844208452084620847208482084920850208512085220853208542085520856208572085820859208602086120862208632086420865208662086720868208692087020871208722087320874208752087620877208782087920880208812088220883208842088520886208872088820889208902089120892208932089420895208962089720898208992090020901209022090320904209052090620907209082090920910209112091220913209142091520916209172091820919209202092120922209232092420925209262092720928209292093020931209322093320934209352093620937209382093920940209412094220943209442094520946209472094820949209502095120952209532095420955209562095720958209592096020961209622096320964209652096620967209682096920970209712097220973209742097520976209772097820979209802098120982209832098420985209862098720988209892099020991209922099320994209952099620997209982099921000210012100221003210042100521006210072100821009210102101121012210132101421015210162101721018210192102021021210222102321024210252102621027210282102921030210312103221033210342103521036210372103821039210402104121042210432104421045210462104721048210492105021051210522105321054210552105621057210582105921060210612106221063210642106521066210672106821069210702107121072210732107421075210762107721078210792108021081210822108321084210852108621087210882108921090210912109221093210942109521096210972109821099211002110121102211032110421105211062110721108211092111021111211122111321114211152111621117211182111921120211212112221123211242112521126211272112821129211302113121132211332113421135211362113721138211392114021141211422114321144211452114621147211482114921150211512115221153211542115521156211572115821159211602116121162211632116421165211662116721168211692117021171211722117321174211752117621177211782117921180211812118221183211842118521186211872118821189211902119121192211932119421195211962119721198211992120021201212022120321204212052120621207212082120921210212112121221213212142121521216212172121821219212202122121222212232122421225212262122721228212292123021231212322123321234212352123621237212382123921240212412124221243212442124521246212472124821249212502125121252212532125421255212562125721258212592126021261212622126321264212652126621267212682126921270212712127221273212742127521276212772127821279212802128121282212832128421285212862128721288212892129021291212922129321294212952129621297212982129921300213012130221303213042130521306213072130821309213102131121312213132131421315213162131721318213192132021321213222132321324213252132621327213282132921330213312133221333213342133521336213372133821339213402134121342213432134421345213462134721348213492135021351213522135321354213552135621357213582135921360213612136221363213642136521366213672136821369213702137121372213732137421375213762137721378213792138021381213822138321384213852138621387213882138921390213912139221393213942139521396213972139821399214002140121402214032140421405214062140721408214092141021411214122141321414214152141621417214182141921420214212142221423214242142521426214272142821429214302143121432214332143421435214362143721438214392144021441214422144321444214452144621447214482144921450214512145221453214542145521456214572145821459214602146121462214632146421465214662146721468214692147021471214722147321474214752147621477214782147921480214812148221483214842148521486214872148821489214902149121492214932149421495214962149721498214992150021501215022150321504215052150621507215082150921510215112151221513215142151521516215172151821519215202152121522215232152421525215262152721528215292153021531215322153321534215352153621537215382153921540215412154221543215442154521546215472154821549215502155121552215532155421555215562155721558215592156021561215622156321564215652156621567215682156921570215712157221573215742157521576215772157821579215802158121582215832158421585215862158721588215892159021591215922159321594215952159621597215982159921600216012160221603216042160521606216072160821609216102161121612216132161421615216162161721618216192162021621216222162321624216252162621627216282162921630216312163221633216342163521636216372163821639216402164121642216432164421645216462164721648216492165021651216522165321654216552165621657216582165921660216612166221663216642166521666216672166821669216702167121672216732167421675216762167721678216792168021681216822168321684216852168621687216882168921690216912169221693216942169521696216972169821699217002170121702217032170421705217062170721708217092171021711217122171321714217152171621717217182171921720217212172221723217242172521726217272172821729217302173121732217332173421735217362173721738217392174021741217422174321744217452174621747217482174921750217512175221753217542175521756217572175821759217602176121762217632176421765217662176721768217692177021771217722177321774217752177621777217782177921780217812178221783217842178521786217872178821789217902179121792217932179421795217962179721798217992180021801218022180321804218052180621807218082180921810218112181221813218142181521816218172181821819218202182121822218232182421825218262182721828218292183021831218322183321834218352183621837218382183921840218412184221843218442184521846218472184821849218502185121852218532185421855218562185721858218592186021861218622186321864218652186621867218682186921870218712187221873218742187521876218772187821879218802188121882218832188421885218862188721888218892189021891218922189321894218952189621897218982189921900219012190221903219042190521906219072190821909219102191121912219132191421915219162191721918219192192021921219222192321924219252192621927219282192921930219312193221933219342193521936219372193821939219402194121942219432194421945219462194721948219492195021951219522195321954219552195621957219582195921960219612196221963219642196521966219672196821969219702197121972219732197421975219762197721978219792198021981219822198321984219852198621987219882198921990219912199221993219942199521996219972199821999220002200122002220032200422005220062200722008220092201022011220122201322014220152201622017220182201922020220212202222023220242202522026220272202822029220302203122032220332203422035220362203722038220392204022041220422204322044220452204622047220482204922050220512205222053220542205522056220572205822059220602206122062220632206422065220662206722068220692207022071220722207322074220752207622077220782207922080220812208222083220842208522086220872208822089220902209122092220932209422095220962209722098220992210022101221022210322104221052210622107221082210922110221112211222113221142211522116221172211822119221202212122122221232212422125221262212722128221292213022131221322213322134221352213622137221382213922140221412214222143221442214522146221472214822149221502215122152221532215422155221562215722158221592216022161221622216322164221652216622167221682216922170221712217222173221742217522176221772217822179221802218122182221832218422185221862218722188221892219022191221922219322194221952219622197221982219922200222012220222203222042220522206222072220822209222102221122212222132221422215222162221722218222192222022221222222222322224222252222622227222282222922230222312223222233222342223522236222372223822239222402224122242222432224422245222462224722248222492225022251222522225322254222552225622257222582225922260222612226222263222642226522266222672226822269222702227122272222732227422275222762227722278222792228022281222822228322284222852228622287222882228922290222912229222293222942229522296222972229822299223002230122302223032230422305223062230722308223092231022311223122231322314223152231622317223182231922320223212232222323223242232522326223272232822329223302233122332223332233422335223362233722338223392234022341223422234322344223452234622347223482234922350223512235222353223542235522356223572235822359223602236122362223632236422365223662236722368223692237022371223722237322374223752237622377223782237922380223812238222383223842238522386223872238822389223902239122392223932239422395223962239722398223992240022401224022240322404224052240622407224082240922410224112241222413224142241522416224172241822419224202242122422224232242422425224262242722428224292243022431224322243322434224352243622437224382243922440224412244222443224442244522446224472244822449224502245122452224532245422455224562245722458224592246022461224622246322464224652246622467224682246922470224712247222473224742247522476224772247822479224802248122482224832248422485224862248722488224892249022491224922249322494224952249622497224982249922500225012250222503225042250522506225072250822509225102251122512225132251422515225162251722518225192252022521225222252322524225252252622527225282252922530225312253222533225342253522536225372253822539225402254122542225432254422545225462254722548225492255022551225522255322554225552255622557225582255922560225612256222563225642256522566225672256822569225702257122572225732257422575225762257722578225792258022581225822258322584225852258622587225882258922590225912259222593225942259522596225972259822599226002260122602226032260422605226062260722608226092261022611226122261322614226152261622617226182261922620226212262222623226242262522626226272262822629226302263122632226332263422635226362263722638226392264022641226422264322644226452264622647226482264922650226512265222653226542265522656226572265822659226602266122662226632266422665226662266722668226692267022671226722267322674226752267622677226782267922680226812268222683226842268522686226872268822689226902269122692226932269422695226962269722698226992270022701227022270322704227052270622707227082270922710227112271222713227142271522716227172271822719227202272122722227232272422725227262272722728227292273022731227322273322734227352273622737227382273922740227412274222743227442274522746227472274822749227502275122752227532275422755227562275722758227592276022761227622276322764227652276622767227682276922770227712277222773227742277522776227772277822779227802278122782227832278422785227862278722788227892279022791227922279322794227952279622797227982279922800228012280222803228042280522806228072280822809228102281122812228132281422815228162281722818228192282022821228222282322824228252282622827228282282922830228312283222833228342283522836228372283822839228402284122842228432284422845228462284722848228492285022851228522285322854228552285622857228582285922860228612286222863228642286522866228672286822869228702287122872228732287422875228762287722878228792288022881228822288322884228852288622887228882288922890228912289222893228942289522896228972289822899229002290122902229032290422905229062290722908229092291022911229122291322914229152291622917229182291922920229212292222923229242292522926229272292822929229302293122932229332293422935229362293722938229392294022941229422294322944229452294622947229482294922950229512295222953229542295522956229572295822959229602296122962229632296422965229662296722968229692297022971229722297322974229752297622977229782297922980229812298222983229842298522986229872298822989229902299122992229932299422995229962299722998229992300023001230022300323004230052300623007230082300923010230112301223013230142301523016230172301823019230202302123022230232302423025230262302723028230292303023031230322303323034230352303623037230382303923040230412304223043230442304523046230472304823049230502305123052230532305423055230562305723058230592306023061230622306323064230652306623067230682306923070230712307223073230742307523076230772307823079230802308123082230832308423085230862308723088230892309023091230922309323094230952309623097230982309923100231012310223103231042310523106231072310823109231102311123112231132311423115231162311723118231192312023121231222312323124231252312623127231282312923130231312313223133231342313523136231372313823139231402314123142231432314423145231462314723148231492315023151231522315323154231552315623157231582315923160231612316223163231642316523166231672316823169231702317123172231732317423175231762317723178231792318023181231822318323184231852318623187231882318923190231912319223193231942319523196231972319823199232002320123202232032320423205232062320723208232092321023211232122321323214232152321623217232182321923220232212322223223232242322523226232272322823229232302323123232232332323423235232362323723238232392324023241232422324323244232452324623247232482324923250232512325223253232542325523256232572325823259232602326123262232632326423265232662326723268232692327023271232722327323274232752327623277232782327923280232812328223283232842328523286232872328823289232902329123292232932329423295232962329723298232992330023301233022330323304233052330623307233082330923310233112331223313233142331523316233172331823319233202332123322233232332423325233262332723328233292333023331233322333323334233352333623337233382333923340233412334223343233442334523346233472334823349233502335123352233532335423355233562335723358233592336023361233622336323364233652336623367233682336923370233712337223373233742337523376233772337823379233802338123382233832338423385233862338723388233892339023391233922339323394233952339623397233982339923400234012340223403234042340523406234072340823409234102341123412234132341423415234162341723418234192342023421234222342323424234252342623427234282342923430234312343223433234342343523436234372343823439234402344123442234432344423445234462344723448234492345023451234522345323454234552345623457234582345923460234612346223463234642346523466234672346823469234702347123472234732347423475234762347723478234792348023481234822348323484234852348623487234882348923490234912349223493234942349523496234972349823499235002350123502235032350423505235062350723508235092351023511235122351323514235152351623517235182351923520235212352223523235242352523526235272352823529235302353123532235332353423535235362353723538235392354023541235422354323544235452354623547235482354923550235512355223553235542355523556235572355823559235602356123562235632356423565235662356723568235692357023571235722357323574235752357623577235782357923580235812358223583235842358523586235872358823589235902359123592235932359423595235962359723598235992360023601236022360323604236052360623607236082360923610236112361223613236142361523616236172361823619236202362123622236232362423625236262362723628236292363023631236322363323634236352363623637236382363923640236412364223643236442364523646236472364823649236502365123652236532365423655236562365723658236592366023661236622366323664236652366623667236682366923670236712367223673236742367523676236772367823679236802368123682236832368423685236862368723688236892369023691236922369323694236952369623697236982369923700237012370223703237042370523706237072370823709237102371123712237132371423715237162371723718237192372023721237222372323724237252372623727237282372923730237312373223733237342373523736237372373823739237402374123742237432374423745237462374723748237492375023751237522375323754237552375623757237582375923760237612376223763237642376523766237672376823769237702377123772237732377423775237762377723778237792378023781237822378323784237852378623787237882378923790237912379223793237942379523796237972379823799238002380123802238032380423805238062380723808238092381023811238122381323814238152381623817238182381923820238212382223823238242382523826238272382823829238302383123832238332383423835238362383723838238392384023841238422384323844238452384623847238482384923850238512385223853238542385523856238572385823859238602386123862238632386423865238662386723868238692387023871238722387323874238752387623877238782387923880238812388223883238842388523886238872388823889238902389123892238932389423895238962389723898238992390023901239022390323904239052390623907239082390923910239112391223913239142391523916239172391823919239202392123922239232392423925239262392723928239292393023931239322393323934239352393623937239382393923940239412394223943239442394523946239472394823949239502395123952239532395423955239562395723958239592396023961239622396323964239652396623967239682396923970239712397223973239742397523976239772397823979239802398123982239832398423985239862398723988239892399023991239922399323994239952399623997239982399924000240012400224003240042400524006240072400824009240102401124012240132401424015240162401724018240192402024021240222402324024240252402624027240282402924030240312403224033240342403524036240372403824039240402404124042240432404424045240462404724048240492405024051240522405324054240552405624057240582405924060240612406224063240642406524066240672406824069240702407124072240732407424075240762407724078240792408024081240822408324084240852408624087240882408924090240912409224093240942409524096240972409824099241002410124102241032410424105241062410724108241092411024111241122411324114241152411624117241182411924120241212412224123241242412524126241272412824129241302413124132241332413424135241362413724138241392414024141241422414324144241452414624147241482414924150241512415224153241542415524156241572415824159241602416124162241632416424165241662416724168241692417024171241722417324174241752417624177241782417924180241812418224183241842418524186241872418824189241902419124192241932419424195241962419724198241992420024201242022420324204242052420624207242082420924210242112421224213242142421524216242172421824219242202422124222242232422424225242262422724228242292423024231242322423324234242352423624237242382423924240242412424224243242442424524246242472424824249242502425124252242532425424255242562425724258242592426024261242622426324264242652426624267242682426924270242712427224273242742427524276242772427824279242802428124282242832428424285242862428724288242892429024291242922429324294242952429624297242982429924300243012430224303243042430524306243072430824309243102431124312243132431424315243162431724318243192432024321243222432324324243252432624327243282432924330243312433224333243342433524336243372433824339243402434124342243432434424345243462434724348243492435024351243522435324354243552435624357243582435924360243612436224363243642436524366243672436824369243702437124372243732437424375243762437724378243792438024381243822438324384243852438624387243882438924390243912439224393243942439524396243972439824399244002440124402244032440424405244062440724408244092441024411244122441324414244152441624417244182441924420244212442224423244242442524426244272442824429244302443124432244332443424435244362443724438244392444024441244422444324444244452444624447244482444924450244512445224453244542445524456244572445824459244602446124462244632446424465244662446724468244692447024471244722447324474244752447624477244782447924480244812448224483244842448524486244872448824489244902449124492244932449424495244962449724498244992450024501245022450324504245052450624507245082450924510245112451224513245142451524516245172451824519245202452124522245232452424525245262452724528245292453024531245322453324534245352453624537245382453924540245412454224543245442454524546245472454824549245502455124552245532455424555245562455724558245592456024561245622456324564245652456624567245682456924570245712457224573245742457524576245772457824579245802458124582245832458424585245862458724588245892459024591245922459324594245952459624597245982459924600246012460224603246042460524606246072460824609246102461124612246132461424615246162461724618246192462024621246222462324624246252462624627246282462924630246312463224633246342463524636246372463824639246402464124642246432464424645246462464724648246492465024651246522465324654246552465624657246582465924660246612466224663246642466524666246672466824669246702467124672246732467424675246762467724678246792468024681246822468324684246852468624687246882468924690246912469224693246942469524696246972469824699247002470124702247032470424705247062470724708247092471024711247122471324714247152471624717247182471924720247212472224723247242472524726247272472824729247302473124732247332473424735247362473724738247392474024741247422474324744247452474624747247482474924750247512475224753247542475524756247572475824759247602476124762247632476424765247662476724768247692477024771247722477324774247752477624777247782477924780247812478224783247842478524786247872478824789247902479124792247932479424795247962479724798247992480024801248022480324804248052480624807248082480924810248112481224813248142481524816248172481824819248202482124822248232482424825248262482724828248292483024831248322483324834248352483624837248382483924840248412484224843248442484524846248472484824849248502485124852248532485424855248562485724858248592486024861248622486324864248652486624867248682486924870248712487224873248742487524876248772487824879248802488124882248832488424885248862488724888248892489024891248922489324894248952489624897248982489924900249012490224903249042490524906249072490824909249102491124912249132491424915249162491724918249192492024921249222492324924249252492624927249282492924930249312493224933249342493524936249372493824939249402494124942249432494424945249462494724948249492495024951249522495324954249552495624957249582495924960249612496224963249642496524966249672496824969249702497124972249732497424975249762497724978249792498024981249822498324984249852498624987249882498924990249912499224993249942499524996249972499824999250002500125002250032500425005250062500725008250092501025011250122501325014250152501625017250182501925020250212502225023250242502525026250272502825029250302503125032250332503425035250362503725038250392504025041250422504325044250452504625047250482504925050250512505225053250542505525056250572505825059250602506125062250632506425065250662506725068250692507025071250722507325074250752507625077250782507925080250812508225083250842508525086250872508825089250902509125092250932509425095250962509725098250992510025101251022510325104251052510625107251082510925110251112511225113251142511525116251172511825119251202512125122251232512425125251262512725128251292513025131251322513325134251352513625137251382513925140251412514225143251442514525146251472514825149251502515125152251532515425155251562515725158251592516025161251622516325164251652516625167251682516925170251712517225173251742517525176251772517825179251802518125182251832518425185251862518725188251892519025191251922519325194251952519625197251982519925200252012520225203252042520525206252072520825209252102521125212252132521425215252162521725218252192522025221252222522325224252252522625227252282522925230252312523225233252342523525236252372523825239252402524125242252432524425245252462524725248252492525025251252522525325254252552525625257252582525925260252612526225263252642526525266252672526825269252702527125272252732527425275252762527725278252792528025281252822528325284252852528625287252882528925290252912529225293252942529525296252972529825299253002530125302253032530425305253062530725308253092531025311253122531325314253152531625317253182531925320253212532225323253242532525326253272532825329253302533125332253332533425335253362533725338253392534025341253422534325344253452534625347253482534925350253512535225353253542535525356253572535825359253602536125362253632536425365253662536725368253692537025371253722537325374253752537625377253782537925380253812538225383253842538525386253872538825389253902539125392253932539425395253962539725398253992540025401254022540325404254052540625407254082540925410254112541225413254142541525416254172541825419254202542125422254232542425425254262542725428254292543025431254322543325434254352543625437254382543925440254412544225443254442544525446254472544825449254502545125452254532545425455254562545725458254592546025461254622546325464254652546625467254682546925470254712547225473254742547525476254772547825479254802548125482254832548425485254862548725488254892549025491254922549325494254952549625497254982549925500255012550225503255042550525506255072550825509255102551125512255132551425515255162551725518255192552025521255222552325524255252552625527255282552925530255312553225533255342553525536255372553825539255402554125542255432554425545255462554725548255492555025551255522555325554255552555625557255582555925560255612556225563255642556525566255672556825569255702557125572255732557425575255762557725578255792558025581255822558325584255852558625587255882558925590255912559225593255942559525596255972559825599256002560125602256032560425605256062560725608256092561025611256122561325614256152561625617256182561925620256212562225623256242562525626256272562825629256302563125632256332563425635256362563725638256392564025641256422564325644256452564625647256482564925650256512565225653256542565525656256572565825659256602566125662256632566425665256662566725668256692567025671256722567325674256752567625677256782567925680256812568225683256842568525686256872568825689256902569125692256932569425695256962569725698256992570025701257022570325704257052570625707257082570925710257112571225713257142571525716257172571825719257202572125722257232572425725257262572725728257292573025731257322573325734257352573625737257382573925740257412574225743257442574525746257472574825749257502575125752257532575425755257562575725758257592576025761257622576325764257652576625767257682576925770257712577225773257742577525776257772577825779257802578125782257832578425785257862578725788257892579025791257922579325794257952579625797257982579925800258012580225803258042580525806258072580825809258102581125812258132581425815258162581725818258192582025821258222582325824258252582625827258282582925830258312583225833258342583525836258372583825839258402584125842258432584425845258462584725848258492585025851258522585325854258552585625857258582585925860258612586225863258642586525866258672586825869258702587125872258732587425875258762587725878258792588025881258822588325884258852588625887258882588925890258912589225893258942589525896258972589825899259002590125902259032590425905259062590725908259092591025911259122591325914259152591625917259182591925920259212592225923259242592525926259272592825929259302593125932259332593425935259362593725938259392594025941259422594325944259452594625947259482594925950259512595225953259542595525956259572595825959259602596125962259632596425965259662596725968259692597025971259722597325974259752597625977259782597925980259812598225983259842598525986259872598825989259902599125992259932599425995259962599725998259992600026001260022600326004260052600626007260082600926010260112601226013260142601526016260172601826019260202602126022260232602426025260262602726028260292603026031260322603326034260352603626037260382603926040260412604226043260442604526046260472604826049260502605126052260532605426055260562605726058260592606026061260622606326064260652606626067260682606926070260712607226073260742607526076260772607826079260802608126082260832608426085260862608726088260892609026091260922609326094260952609626097260982609926100261012610226103261042610526106261072610826109261102611126112261132611426115261162611726118261192612026121261222612326124261252612626127261282612926130261312613226133261342613526136261372613826139261402614126142261432614426145261462614726148261492615026151261522615326154261552615626157261582615926160261612616226163261642616526166261672616826169261702617126172261732617426175261762617726178261792618026181261822618326184261852618626187261882618926190261912619226193261942619526196261972619826199262002620126202262032620426205262062620726208262092621026211262122621326214262152621626217262182621926220262212622226223262242622526226262272622826229262302623126232262332623426235262362623726238262392624026241262422624326244262452624626247262482624926250262512625226253262542625526256262572625826259262602626126262262632626426265262662626726268262692627026271262722627326274262752627626277262782627926280262812628226283262842628526286262872628826289262902629126292262932629426295262962629726298262992630026301263022630326304263052630626307263082630926310263112631226313263142631526316263172631826319263202632126322263232632426325263262632726328263292633026331263322633326334263352633626337263382633926340263412634226343263442634526346263472634826349263502635126352263532635426355263562635726358263592636026361263622636326364263652636626367263682636926370263712637226373263742637526376263772637826379263802638126382263832638426385263862638726388263892639026391263922639326394263952639626397263982639926400264012640226403264042640526406264072640826409264102641126412264132641426415264162641726418264192642026421264222642326424264252642626427264282642926430264312643226433264342643526436264372643826439264402644126442264432644426445264462644726448264492645026451264522645326454264552645626457264582645926460264612646226463264642646526466264672646826469264702647126472264732647426475264762647726478264792648026481264822648326484264852648626487264882648926490264912649226493264942649526496264972649826499265002650126502265032650426505265062650726508265092651026511265122651326514265152651626517265182651926520265212652226523265242652526526265272652826529265302653126532265332653426535265362653726538265392654026541265422654326544265452654626547265482654926550265512655226553265542655526556265572655826559265602656126562265632656426565265662656726568265692657026571265722657326574265752657626577265782657926580265812658226583265842658526586265872658826589265902659126592265932659426595265962659726598265992660026601266022660326604266052660626607266082660926610266112661226613266142661526616266172661826619266202662126622266232662426625266262662726628266292663026631266322663326634266352663626637266382663926640266412664226643266442664526646266472664826649266502665126652266532665426655266562665726658266592666026661266622666326664266652666626667266682666926670266712667226673266742667526676266772667826679266802668126682266832668426685266862668726688266892669026691266922669326694266952669626697266982669926700267012670226703267042670526706267072670826709267102671126712267132671426715267162671726718267192672026721267222672326724267252672626727267282672926730267312673226733267342673526736267372673826739267402674126742267432674426745267462674726748267492675026751267522675326754267552675626757267582675926760267612676226763267642676526766267672676826769267702677126772267732677426775267762677726778267792678026781267822678326784267852678626787267882678926790267912679226793267942679526796267972679826799268002680126802268032680426805268062680726808268092681026811268122681326814268152681626817268182681926820268212682226823268242682526826268272682826829268302683126832268332683426835268362683726838268392684026841268422684326844268452684626847268482684926850268512685226853268542685526856268572685826859268602686126862268632686426865268662686726868268692687026871268722687326874268752687626877268782687926880268812688226883268842688526886268872688826889268902689126892268932689426895268962689726898268992690026901269022690326904269052690626907269082690926910269112691226913269142691526916269172691826919269202692126922269232692426925269262692726928269292693026931269322693326934269352693626937269382693926940269412694226943269442694526946269472694826949269502695126952269532695426955269562695726958269592696026961269622696326964269652696626967269682696926970269712697226973269742697526976269772697826979269802698126982269832698426985269862698726988269892699026991269922699326994269952699626997269982699927000270012700227003270042700527006270072700827009270102701127012270132701427015270162701727018270192702027021270222702327024270252702627027270282702927030270312703227033270342703527036270372703827039270402704127042270432704427045270462704727048270492705027051270522705327054270552705627057270582705927060270612706227063270642706527066270672706827069270702707127072270732707427075270762707727078270792708027081270822708327084270852708627087270882708927090270912709227093270942709527096270972709827099271002710127102271032710427105271062710727108271092711027111271122711327114271152711627117271182711927120271212712227123271242712527126271272712827129271302713127132271332713427135271362713727138271392714027141271422714327144271452714627147271482714927150271512715227153271542715527156271572715827159271602716127162271632716427165271662716727168271692717027171271722717327174271752717627177271782717927180271812718227183271842718527186271872718827189271902719127192271932719427195271962719727198271992720027201272022720327204272052720627207272082720927210272112721227213272142721527216272172721827219272202722127222272232722427225272262722727228272292723027231272322723327234272352723627237272382723927240272412724227243272442724527246272472724827249272502725127252272532725427255272562725727258272592726027261272622726327264272652726627267272682726927270272712727227273272742727527276272772727827279272802728127282272832728427285272862728727288272892729027291272922729327294272952729627297272982729927300273012730227303273042730527306273072730827309273102731127312273132731427315273162731727318273192732027321273222732327324273252732627327273282732927330273312733227333273342733527336273372733827339273402734127342273432734427345273462734727348273492735027351273522735327354273552735627357273582735927360273612736227363273642736527366273672736827369273702737127372273732737427375273762737727378273792738027381273822738327384273852738627387273882738927390273912739227393273942739527396273972739827399274002740127402274032740427405274062740727408274092741027411274122741327414274152741627417274182741927420274212742227423274242742527426274272742827429274302743127432274332743427435274362743727438274392744027441274422744327444274452744627447274482744927450274512745227453274542745527456274572745827459274602746127462274632746427465274662746727468274692747027471274722747327474274752747627477274782747927480274812748227483274842748527486274872748827489274902749127492274932749427495274962749727498274992750027501275022750327504275052750627507275082750927510275112751227513275142751527516275172751827519275202752127522275232752427525275262752727528275292753027531275322753327534275352753627537275382753927540275412754227543275442754527546275472754827549275502755127552275532755427555275562755727558275592756027561275622756327564275652756627567275682756927570275712757227573275742757527576275772757827579275802758127582275832758427585275862758727588275892759027591275922759327594275952759627597275982759927600276012760227603276042760527606276072760827609276102761127612276132761427615276162761727618276192762027621276222762327624276252762627627276282762927630276312763227633276342763527636276372763827639276402764127642276432764427645276462764727648276492765027651276522765327654276552765627657276582765927660276612766227663276642766527666276672766827669276702767127672276732767427675276762767727678276792768027681276822768327684276852768627687276882768927690276912769227693276942769527696276972769827699277002770127702277032770427705277062770727708277092771027711277122771327714277152771627717277182771927720277212772227723277242772527726277272772827729277302773127732277332773427735277362773727738277392774027741277422774327744277452774627747277482774927750277512775227753277542775527756277572775827759277602776127762277632776427765277662776727768277692777027771277722777327774277752777627777277782777927780277812778227783277842778527786277872778827789277902779127792277932779427795277962779727798277992780027801278022780327804278052780627807278082780927810278112781227813278142781527816278172781827819278202782127822278232782427825278262782727828278292783027831278322783327834278352783627837278382783927840278412784227843278442784527846278472784827849278502785127852278532785427855278562785727858278592786027861278622786327864278652786627867278682786927870278712787227873278742787527876278772787827879278802788127882278832788427885278862788727888278892789027891278922789327894278952789627897278982789927900279012790227903279042790527906279072790827909279102791127912279132791427915279162791727918279192792027921279222792327924279252792627927279282792927930279312793227933279342793527936279372793827939279402794127942279432794427945279462794727948279492795027951279522795327954279552795627957279582795927960279612796227963279642796527966279672796827969279702797127972279732797427975279762797727978279792798027981279822798327984279852798627987279882798927990279912799227993279942799527996279972799827999280002800128002280032800428005280062800728008280092801028011280122801328014280152801628017280182801928020280212802228023280242802528026280272802828029280302803128032280332803428035280362803728038280392804028041280422804328044280452804628047280482804928050280512805228053280542805528056280572805828059280602806128062280632806428065280662806728068280692807028071280722807328074280752807628077280782807928080280812808228083280842808528086280872808828089280902809128092280932809428095280962809728098280992810028101281022810328104281052810628107281082810928110281112811228113281142811528116281172811828119281202812128122281232812428125281262812728128281292813028131281322813328134281352813628137281382813928140281412814228143281442814528146281472814828149281502815128152281532815428155281562815728158281592816028161281622816328164281652816628167281682816928170281712817228173281742817528176281772817828179281802818128182281832818428185281862818728188281892819028191281922819328194281952819628197281982819928200282012820228203282042820528206282072820828209282102821128212282132821428215282162821728218282192822028221282222822328224282252822628227282282822928230282312823228233282342823528236282372823828239282402824128242282432824428245282462824728248282492825028251282522825328254282552825628257282582825928260282612826228263282642826528266282672826828269282702827128272282732827428275282762827728278282792828028281282822828328284282852828628287282882828928290282912829228293282942829528296282972829828299283002830128302283032830428305283062830728308283092831028311283122831328314283152831628317283182831928320283212832228323283242832528326283272832828329283302833128332283332833428335283362833728338283392834028341283422834328344283452834628347283482834928350283512835228353283542835528356283572835828359283602836128362283632836428365283662836728368283692837028371283722837328374283752837628377283782837928380283812838228383283842838528386283872838828389283902839128392283932839428395283962839728398283992840028401284022840328404284052840628407284082840928410284112841228413284142841528416284172841828419284202842128422284232842428425284262842728428284292843028431284322843328434284352843628437284382843928440284412844228443284442844528446284472844828449284502845128452284532845428455284562845728458284592846028461284622846328464284652846628467284682846928470284712847228473284742847528476284772847828479284802848128482284832848428485284862848728488284892849028491284922849328494284952849628497284982849928500285012850228503285042850528506285072850828509285102851128512285132851428515285162851728518285192852028521285222852328524285252852628527285282852928530285312853228533285342853528536285372853828539285402854128542285432854428545285462854728548285492855028551285522855328554285552855628557285582855928560285612856228563285642856528566285672856828569285702857128572285732857428575285762857728578285792858028581285822858328584285852858628587285882858928590285912859228593285942859528596285972859828599286002860128602286032860428605286062860728608286092861028611286122861328614286152861628617286182861928620286212862228623286242862528626286272862828629286302863128632286332863428635286362863728638286392864028641286422864328644286452864628647286482864928650286512865228653286542865528656286572865828659286602866128662286632866428665286662866728668286692867028671286722867328674286752867628677286782867928680286812868228683286842868528686286872868828689286902869128692286932869428695286962869728698286992870028701287022870328704287052870628707287082870928710287112871228713287142871528716287172871828719287202872128722287232872428725287262872728728287292873028731287322873328734287352873628737287382873928740287412874228743287442874528746287472874828749287502875128752287532875428755287562875728758287592876028761287622876328764287652876628767287682876928770287712877228773287742877528776287772877828779287802878128782287832878428785287862878728788287892879028791287922879328794287952879628797287982879928800288012880228803288042880528806288072880828809288102881128812288132881428815288162881728818288192882028821288222882328824288252882628827288282882928830288312883228833288342883528836288372883828839288402884128842288432884428845288462884728848288492885028851288522885328854288552885628857288582885928860288612886228863288642886528866288672886828869288702887128872288732887428875288762887728878288792888028881288822888328884288852888628887288882888928890288912889228893288942889528896288972889828899289002890128902289032890428905289062890728908289092891028911289122891328914289152891628917289182891928920289212892228923289242892528926289272892828929289302893128932289332893428935289362893728938289392894028941289422894328944289452894628947289482894928950289512895228953289542895528956289572895828959289602896128962289632896428965289662896728968289692897028971289722897328974289752897628977289782897928980289812898228983289842898528986289872898828989289902899128992289932899428995289962899728998289992900029001290022900329004290052900629007290082900929010290112901229013290142901529016290172901829019290202902129022290232902429025290262902729028290292903029031290322903329034290352903629037290382903929040290412904229043290442904529046290472904829049290502905129052290532905429055290562905729058290592906029061290622906329064290652906629067290682906929070290712907229073290742907529076290772907829079290802908129082290832908429085290862908729088290892909029091290922909329094290952909629097290982909929100291012910229103291042910529106291072910829109291102911129112291132911429115291162911729118291192912029121291222912329124291252912629127291282912929130291312913229133291342913529136291372913829139291402914129142291432914429145291462914729148291492915029151291522915329154291552915629157291582915929160291612916229163291642916529166291672916829169291702917129172291732917429175291762917729178291792918029181291822918329184291852918629187291882918929190291912919229193291942919529196291972919829199292002920129202292032920429205292062920729208292092921029211292122921329214292152921629217292182921929220292212922229223292242922529226292272922829229292302923129232292332923429235292362923729238292392924029241292422924329244292452924629247292482924929250292512925229253292542925529256292572925829259292602926129262292632926429265292662926729268292692927029271292722927329274292752927629277292782927929280292812928229283292842928529286292872928829289292902929129292292932929429295292962929729298292992930029301293022930329304293052930629307293082930929310293112931229313293142931529316293172931829319293202932129322293232932429325293262932729328293292933029331293322933329334293352933629337293382933929340293412934229343293442934529346293472934829349293502935129352293532935429355293562935729358293592936029361293622936329364293652936629367293682936929370293712937229373293742937529376293772937829379293802938129382293832938429385293862938729388293892939029391293922939329394293952939629397293982939929400294012940229403294042940529406294072940829409294102941129412294132941429415294162941729418294192942029421294222942329424294252942629427294282942929430294312943229433294342943529436294372943829439294402944129442294432944429445294462944729448294492945029451294522945329454294552945629457294582945929460294612946229463294642946529466294672946829469294702947129472294732947429475294762947729478294792948029481294822948329484294852948629487294882948929490294912949229493294942949529496294972949829499295002950129502295032950429505295062950729508295092951029511295122951329514295152951629517295182951929520295212952229523295242952529526295272952829529295302953129532295332953429535295362953729538295392954029541295422954329544295452954629547295482954929550295512955229553295542955529556295572955829559295602956129562295632956429565295662956729568295692957029571295722957329574295752957629577295782957929580295812958229583295842958529586295872958829589295902959129592295932959429595295962959729598295992960029601296022960329604296052960629607296082960929610296112961229613296142961529616296172961829619296202962129622296232962429625296262962729628296292963029631296322963329634296352963629637296382963929640296412964229643296442964529646296472964829649296502965129652296532965429655296562965729658296592966029661296622966329664296652966629667296682966929670296712967229673296742967529676296772967829679296802968129682296832968429685296862968729688296892969029691296922969329694296952969629697296982969929700297012970229703297042970529706297072970829709297102971129712297132971429715297162971729718297192972029721297222972329724297252972629727297282972929730297312973229733297342973529736297372973829739297402974129742297432974429745297462974729748297492975029751297522975329754297552975629757297582975929760297612976229763297642976529766297672976829769297702977129772297732977429775297762977729778297792978029781297822978329784297852978629787297882978929790297912979229793297942979529796297972979829799298002980129802298032980429805298062980729808298092981029811298122981329814298152981629817298182981929820298212982229823298242982529826298272982829829298302983129832298332983429835298362983729838298392984029841298422984329844298452984629847298482984929850298512985229853298542985529856298572985829859298602986129862298632986429865298662986729868298692987029871298722987329874298752987629877298782987929880298812988229883298842988529886298872988829889298902989129892298932989429895298962989729898298992990029901299022990329904299052990629907299082990929910299112991229913299142991529916299172991829919299202992129922299232992429925299262992729928299292993029931299322993329934299352993629937299382993929940299412994229943299442994529946299472994829949299502995129952299532995429955299562995729958299592996029961299622996329964299652996629967299682996929970299712997229973299742997529976299772997829979299802998129982299832998429985299862998729988299892999029991299922999329994299952999629997299982999930000300013000230003300043000530006300073000830009300103001130012300133001430015300163001730018300193002030021300223002330024300253002630027300283002930030300313003230033300343003530036300373003830039300403004130042300433004430045300463004730048300493005030051300523005330054300553005630057300583005930060300613006230063300643006530066300673006830069300703007130072300733007430075300763007730078300793008030081300823008330084300853008630087300883008930090300913009230093300943009530096300973009830099301003010130102301033010430105301063010730108301093011030111301123011330114301153011630117301183011930120301213012230123301243012530126301273012830129301303013130132301333013430135301363013730138301393014030141301423014330144301453014630147301483014930150301513015230153301543015530156301573015830159301603016130162301633016430165301663016730168301693017030171301723017330174301753017630177301783017930180301813018230183301843018530186301873018830189301903019130192301933019430195301963019730198301993020030201302023020330204302053020630207302083020930210302113021230213302143021530216302173021830219302203022130222302233022430225302263022730228302293023030231302323023330234302353023630237302383023930240302413024230243302443024530246302473024830249302503025130252302533025430255302563025730258302593026030261302623026330264302653026630267302683026930270302713027230273302743027530276302773027830279302803028130282302833028430285302863028730288302893029030291302923029330294302953029630297302983029930300303013030230303303043030530306303073030830309303103031130312303133031430315303163031730318303193032030321303223032330324303253032630327303283032930330303313033230333303343033530336303373033830339303403034130342303433034430345303463034730348303493035030351303523035330354303553035630357303583035930360303613036230363303643036530366303673036830369303703037130372303733037430375303763037730378303793038030381303823038330384303853038630387303883038930390303913039230393303943039530396303973039830399304003040130402304033040430405304063040730408304093041030411304123041330414304153041630417304183041930420304213042230423304243042530426304273042830429304303043130432304333043430435304363043730438304393044030441304423044330444304453044630447304483044930450304513045230453304543045530456304573045830459304603046130462304633046430465304663046730468304693047030471304723047330474304753047630477304783047930480304813048230483304843048530486304873048830489304903049130492304933049430495304963049730498304993050030501305023050330504305053050630507305083050930510305113051230513305143051530516305173051830519305203052130522305233052430525305263052730528305293053030531305323053330534305353053630537305383053930540305413054230543305443054530546305473054830549305503055130552305533055430555305563055730558305593056030561305623056330564305653056630567305683056930570305713057230573305743057530576305773057830579305803058130582305833058430585305863058730588305893059030591305923059330594305953059630597305983059930600306013060230603306043060530606306073060830609306103061130612306133061430615306163061730618306193062030621306223062330624306253062630627306283062930630306313063230633306343063530636306373063830639306403064130642306433064430645306463064730648306493065030651306523065330654306553065630657306583065930660306613066230663306643066530666306673066830669306703067130672306733067430675306763067730678306793068030681306823068330684306853068630687306883068930690306913069230693306943069530696306973069830699307003070130702307033070430705307063070730708307093071030711307123071330714307153071630717307183071930720307213072230723307243072530726307273072830729307303073130732307333073430735307363073730738307393074030741307423074330744307453074630747307483074930750307513075230753307543075530756307573075830759307603076130762307633076430765307663076730768307693077030771307723077330774307753077630777307783077930780307813078230783307843078530786307873078830789307903079130792307933079430795307963079730798307993080030801308023080330804308053080630807308083080930810308113081230813308143081530816308173081830819308203082130822308233082430825308263082730828308293083030831308323083330834308353083630837308383083930840308413084230843308443084530846308473084830849308503085130852308533085430855308563085730858308593086030861308623086330864308653086630867308683086930870308713087230873308743087530876308773087830879308803088130882308833088430885308863088730888308893089030891308923089330894308953089630897308983089930900309013090230903309043090530906309073090830909309103091130912309133091430915309163091730918309193092030921309223092330924309253092630927309283092930930309313093230933309343093530936309373093830939309403094130942309433094430945309463094730948309493095030951309523095330954309553095630957309583095930960309613096230963309643096530966309673096830969309703097130972309733097430975309763097730978309793098030981309823098330984309853098630987309883098930990309913099230993309943099530996309973099830999310003100131002310033100431005310063100731008310093101031011310123101331014310153101631017310183101931020310213102231023310243102531026310273102831029310303103131032310333103431035310363103731038310393104031041310423104331044310453104631047310483104931050310513105231053310543105531056310573105831059310603106131062310633106431065310663106731068310693107031071310723107331074310753107631077310783107931080310813108231083310843108531086310873108831089310903109131092310933109431095310963109731098310993110031101311023110331104311053110631107311083110931110311113111231113311143111531116311173111831119311203112131122311233112431125311263112731128311293113031131311323113331134311353113631137311383113931140311413114231143311443114531146311473114831149311503115131152311533115431155311563115731158311593116031161311623116331164311653116631167311683116931170311713117231173311743117531176311773117831179311803118131182311833118431185311863118731188311893119031191311923119331194311953119631197311983119931200312013120231203312043120531206312073120831209312103121131212312133121431215312163121731218312193122031221312223122331224312253122631227312283122931230312313123231233312343123531236312373123831239312403124131242312433124431245312463124731248312493125031251312523125331254312553125631257312583125931260312613126231263312643126531266312673126831269312703127131272312733127431275312763127731278312793128031281312823128331284312853128631287312883128931290312913129231293312943129531296312973129831299313003130131302313033130431305313063130731308313093131031311313123131331314313153131631317313183131931320313213132231323313243132531326313273132831329313303133131332313333133431335313363133731338313393134031341313423134331344313453134631347313483134931350313513135231353313543135531356313573135831359313603136131362313633136431365313663136731368313693137031371313723137331374313753137631377313783137931380313813138231383313843138531386313873138831389313903139131392313933139431395313963139731398313993140031401314023140331404314053140631407314083140931410314113141231413314143141531416314173141831419314203142131422314233142431425314263142731428314293143031431314323143331434314353143631437314383143931440314413144231443314443144531446314473144831449314503145131452314533145431455314563145731458314593146031461314623146331464314653146631467314683146931470314713147231473314743147531476314773147831479314803148131482314833148431485314863148731488314893149031491314923149331494314953149631497314983149931500315013150231503315043150531506315073150831509315103151131512315133151431515315163151731518315193152031521315223152331524315253152631527315283152931530315313153231533315343153531536315373153831539315403154131542315433154431545315463154731548315493155031551315523155331554315553155631557315583155931560315613156231563315643156531566315673156831569315703157131572315733157431575315763157731578315793158031581315823158331584315853158631587315883158931590315913159231593315943159531596315973159831599316003160131602316033160431605316063160731608316093161031611316123161331614316153161631617316183161931620316213162231623316243162531626316273162831629316303163131632316333163431635316363163731638316393164031641316423164331644316453164631647316483164931650316513165231653316543165531656316573165831659316603166131662316633166431665316663166731668316693167031671316723167331674316753167631677316783167931680316813168231683316843168531686316873168831689316903169131692316933169431695316963169731698316993170031701317023170331704317053170631707317083170931710317113171231713317143171531716317173171831719317203172131722317233172431725317263172731728317293173031731317323173331734317353173631737317383173931740317413174231743317443174531746317473174831749317503175131752317533175431755317563175731758317593176031761317623176331764317653176631767317683176931770317713177231773317743177531776317773177831779317803178131782317833178431785317863178731788317893179031791317923179331794317953179631797317983179931800318013180231803318043180531806318073180831809318103181131812318133181431815318163181731818318193182031821318223182331824318253182631827318283182931830318313183231833
  1. #ifndef UFBX_UFBX_C_INCLUDED
  2. #define UFBX_UFBX_C_INCLUDED
  3. #if defined(UFBX_HEADER_PATH)
  4. #include UFBX_HEADER_PATH
  5. #else
  6. #include "ufbx.h"
  7. #endif
  8. // -- User configuration
  9. // User configuration:
  10. // UFBX_REGRESSION Enable regression mode for development
  11. // UFBX_UBSAN Explicitly enable undefined behavior sanitizer workarounds
  12. // UFBX_NO_UNALIGNED_LOADS Do not use unaligned loads even when they are supported
  13. // UFBX_USE_UNALIGNED_LOADS Forcibly use unaligned loads on unknown platforms
  14. // UFBX_USE_SSE Explicitly enable SSE2 support (for x86)
  15. // UFBX_HAS_FTELLO Allow ufbx to use `ftello()` to measure file size
  16. // UFBX_WASM_32BIT Optimize WASM for 32-bit architectures
  17. // UFBX_TRACE Log calls of `ufbxi_check()` for tracing execution
  18. // UFBX_LITTLE_ENDIAN=0/1 Explicitly define little/big endian architecture
  19. // UFBX_PATH_SEPARATOR='' Specify default platform path separator
  20. // Mostly internal for debugging:
  21. // UFBX_STATIC_ANALYSIS Enable static analysis augmentation
  22. // UFBX_DEBUG_BINARY_SEARCH Force using binary search for debugging
  23. // UFBX_EXTENSIVE_THREADING Use threads for small inputs
  24. #if defined(UFBX_CONFIG_SOURCE)
  25. #include UFBX_CONFIG_SOURCE
  26. #endif
  27. // -- Configuration
  28. #define UFBXI_MAX_NON_ARRAY_VALUES 8
  29. #define UFBXI_MAX_NODE_DEPTH 32
  30. #define UFBXI_MAX_XML_DEPTH 32
  31. #define UFBXI_MAX_SKIP_SIZE 0x40000000
  32. #define UFBXI_MAP_MAX_SCAN 32
  33. #define UFBXI_KD_FAST_DEPTH 6
  34. #define UFBXI_HUGE_MAX_SCAN 16
  35. #define UFBXI_MIN_FILE_FORMAT_LOOKAHEAD 32
  36. #define UFBXI_FACE_GROUP_HASH_BITS 8
  37. #define UFBXI_MIN_THREADED_DEFLATE_BYTES 256
  38. #define UFBXI_MIN_THREADED_ASCII_VALUES 64
  39. #define UFBXI_GEOMETRY_CACHE_BUFFER_SIZE 512
  40. #ifndef UFBXI_MAX_NURBS_ORDER
  41. #define UFBXI_MAX_NURBS_ORDER 128
  42. #endif
  43. // By default enough to have squares be non-denormal
  44. #ifndef UFBX_EPSILON
  45. #define UFBX_EPSILON (sizeof(ufbx_real) == sizeof(float) ? \
  46. (ufbx_real)1.0842021795674597e-19f : (ufbx_real)1.4916681462400413e-154)
  47. #endif
  48. // -- Feature exclusion
  49. #if !defined(UFBX_MINIMAL)
  50. #if !defined(UFBX_NO_SUBDIVISION)
  51. #define UFBXI_FEATURE_SUBDIVISION 1
  52. #endif
  53. #if !defined(UFBX_NO_TESSELLATION)
  54. #define UFBXI_FEATURE_TESSELLATION 1
  55. #endif
  56. #if !defined(UFBX_NO_GEOMETRY_CACHE)
  57. #define UFBXI_FEATURE_GEOMETRY_CACHE 1
  58. #endif
  59. #if !defined(UFBX_NO_SCENE_EVALUATION)
  60. #define UFBXI_FEATURE_SCENE_EVALUATION 1
  61. #endif
  62. #if !defined(UFBX_NO_SKINNING_EVALUATION)
  63. #define UFBXI_FEATURE_SKINNING_EVALUATION 1
  64. #endif
  65. #if !defined(UFBX_NO_ANIMATION_BAKING)
  66. #define UFBXI_FEATURE_ANIMATION_BAKING 1
  67. #endif
  68. #if !defined(UFBX_NO_TRIANGULATION)
  69. #define UFBXI_FEATURE_TRIANGULATION 1
  70. #endif
  71. #if !defined(UFBX_NO_INDEX_GENERATION)
  72. #define UFBXI_FEATURE_INDEX_GENERATION 1
  73. #endif
  74. #if !defined(UFBX_NO_FORMAT_OBJ)
  75. #define UFBXI_FEATURE_FORMAT_OBJ 1
  76. #endif
  77. #endif
  78. #if defined(UFBX_DEV)
  79. #if !defined(UFBX_NO_ERROR_STACK)
  80. #define UFBXI_FEATURE_ERROR_STACK 1
  81. #endif
  82. #endif
  83. #if !defined(UFBXI_FEATURE_SUBDIVISION) && defined(UFBX_ENABLE_SUBDIVISION)
  84. #define UFBXI_FEATURE_SUBDIVISION 1
  85. #endif
  86. #if !defined(UFBXI_FEATURE_TESSELLATION) && defined(UFBX_ENABLE_TESSELLATION)
  87. #define UFBXI_FEATURE_TESSELLATION 1
  88. #endif
  89. #if !defined(UFBXI_FEATURE_GEOMETRY_CACHE) && defined(UFBX_ENABLE_GEOMETRY_CACHE)
  90. #define UFBXI_FEATURE_GEOMETRY_CACHE 1
  91. #endif
  92. #if !defined(UFBXI_FEATURE_SCENE_EVALUATION) && defined(UFBX_ENABLE_SCENE_EVALUATION)
  93. #define UFBXI_FEATURE_SCENE_EVALUATION 1
  94. #endif
  95. #if !defined(UFBXI_FEATURE_SKINNING_EVALUATION) && defined(UFBX_ENABLE_SKINNING_EVALUATION)
  96. #define UFBXI_FEATURE_SKINNING_EVALUATION 1
  97. #endif
  98. #if !defined(UFBXI_FEATURE_ANIMATION_BAKING) && defined(UFBX_ENABLE_ANIMATION_BAKING)
  99. #define UFBXI_FEATURE_ANIMATION_BAKING 1
  100. #endif
  101. #if !defined(UFBXI_FEATURE_TRIANGULATION) && defined(UFBX_ENABLE_TRIANGULATION)
  102. #define UFBXI_FEATURE_TRIANGULATION 1
  103. #endif
  104. #if !defined(UFBXI_FEATURE_INDEX_GENERATION) && defined(UFBX_ENABLE_INDEX_GENERATION)
  105. #define UFBXI_FEATURE_INDEX_GENERATION 1
  106. #endif
  107. #if !defined(UFBXI_FEATURE_FORMAT_OBJ) && defined(UFBX_ENABLE_FORMAT_OBJ)
  108. #define UFBXI_FEATURE_FORMAT_OBJ 1
  109. #endif
  110. #if !defined(UFBXI_FEATURE_ERROR_STACK) && defined(UFBX_ENABLE_ERROR_STACK)
  111. #define UFBXI_FEATURE_ERROR_STACK 1
  112. #endif
  113. #if !defined(UFBXI_FEATURE_SUBDIVISION)
  114. #define UFBXI_FEATURE_SUBDIVISION 0
  115. #endif
  116. #if !defined(UFBXI_FEATURE_TESSELLATION)
  117. #define UFBXI_FEATURE_TESSELLATION 0
  118. #endif
  119. #if !defined(UFBXI_FEATURE_GEOMETRY_CACHE)
  120. #define UFBXI_FEATURE_GEOMETRY_CACHE 0
  121. #endif
  122. #if !defined(UFBXI_FEATURE_SCENE_EVALUATION)
  123. #define UFBXI_FEATURE_SCENE_EVALUATION 0
  124. #endif
  125. #if !defined(UFBXI_FEATURE_SKINNING_EVALUATION)
  126. #define UFBXI_FEATURE_SKINNING_EVALUATION 0
  127. #endif
  128. #if !defined(UFBXI_FEATURE_ANIMATION_BAKING)
  129. #define UFBXI_FEATURE_ANIMATION_BAKING 0
  130. #endif
  131. #if !defined(UFBXI_FEATURE_TRIANGULATION)
  132. #define UFBXI_FEATURE_TRIANGULATION 0
  133. #endif
  134. #if !defined(UFBXI_FEATURE_INDEX_GENERATION)
  135. #define UFBXI_FEATURE_INDEX_GENERATION 0
  136. #endif
  137. #if !defined(UFBXI_FEATURE_FORMAT_OBJ)
  138. #define UFBXI_FEATURE_FORMAT_OBJ 0
  139. #endif
  140. #if !defined(UFBXI_FEATURE_ERROR_STACK)
  141. #define UFBXI_FEATURE_ERROR_STACK 0
  142. #endif
  143. // Derived features
  144. #if UFBXI_FEATURE_GEOMETRY_CACHE
  145. #define UFBXI_FEATURE_XML 1
  146. #else
  147. #define UFBXI_FEATURE_XML 0
  148. #endif
  149. #if UFBXI_FEATURE_TRIANGULATION
  150. #define UFBXI_FEATURE_KD 1
  151. #else
  152. #define UFBXI_FEATURE_KD 0
  153. #endif
  154. #if !UFBXI_FEATURE_SUBDIVISION || !UFBXI_FEATURE_TESSELLATION || !UFBXI_FEATURE_GEOMETRY_CACHE || !UFBXI_FEATURE_SCENE_EVALUATION || !UFBXI_FEATURE_SKINNING_EVALUATION || !UFBXI_FEATURE_ANIMATION_BAKING || !UFBXI_FEATURE_TRIANGULATION || !UFBXI_FEATURE_INDEX_GENERATION || !UFBXI_FEATURE_XML || !UFBXI_FEATURE_KD || !UFBXI_FEATURE_FORMAT_OBJ
  155. #define UFBXI_PARTIAL_FEATURES 1
  156. #endif
  157. // -- Headers
  158. #include <string.h>
  159. #include <stdlib.h>
  160. #include <stdio.h>
  161. #include <stdarg.h>
  162. #include <locale.h>
  163. #include <float.h>
  164. #if !defined(UFBX_NO_MATH_H)
  165. #include <math.h>
  166. #define UFBX_INFINITY INFINITY
  167. #define UFBX_NAN NAN
  168. #endif
  169. #if !defined(UFBX_MATH_PREFIX)
  170. #define UFBX_MATH_PREFIX
  171. #endif
  172. #define ufbxi_math_cat2(a, b) a##b
  173. #define ufbxi_math_cat(a, b) ufbxi_math_cat2(a, b)
  174. #define ufbxi_math_fn(name) ufbxi_math_cat(UFBX_MATH_PREFIX, name)
  175. #if !defined(UFBX_NO_MATH_DEFINES)
  176. #define ufbx_sqrt ufbxi_math_fn(sqrt)
  177. #define ufbx_fabs ufbxi_math_fn(fabs)
  178. #define ufbx_pow ufbxi_math_fn(pow)
  179. #define ufbx_sin ufbxi_math_fn(sin)
  180. #define ufbx_cos ufbxi_math_fn(cos)
  181. #define ufbx_tan ufbxi_math_fn(tan)
  182. #define ufbx_asin ufbxi_math_fn(asin)
  183. #define ufbx_acos ufbxi_math_fn(acos)
  184. #define ufbx_atan ufbxi_math_fn(atan)
  185. #define ufbx_atan2 ufbxi_math_fn(atan2)
  186. #define ufbx_copysign ufbxi_math_fn(copysign)
  187. #define ufbx_fmin ufbxi_math_fn(fmin)
  188. #define ufbx_fmax ufbxi_math_fn(fmax)
  189. #define ufbx_nextafter ufbxi_math_fn(nextafter)
  190. #define ufbx_rint ufbxi_math_fn(rint)
  191. #define ufbx_ceil ufbxi_math_fn(ceil)
  192. #define ufbx_isnan ufbxi_math_fn(isnan)
  193. #endif
  194. #if defined(UFBX_NO_MATH_H) && !defined(UFBX_NO_MATH_DECLARATIONS)
  195. double ufbx_sqrt(double x);
  196. double ufbx_sin(double x);
  197. double ufbx_cos(double x);
  198. double ufbx_tan(double x);
  199. double ufbx_asin(double x);
  200. double ufbx_acos(double x);
  201. double ufbx_atan(double x);
  202. double ufbx_atan2(double y, double x);
  203. double ufbx_pow(double x, double y);
  204. double ufbx_fmin(double a, double b);
  205. double ufbx_fmax(double a, double b);
  206. double ufbx_fabs(double x);
  207. double ufbx_copysign(double x, double y);
  208. double ufbx_nextafter(double x, double y);
  209. double ufbx_rint(double x);
  210. double ufbx_ceil(double x);
  211. int ufbx_isnan(double x);
  212. #endif
  213. #if !defined(UFBX_INFINITY)
  214. #define UFBX_INFINITY (1e+300 * 1e+300)
  215. #endif
  216. #if !defined(UFBX_NAN)
  217. #define UFBX_NAN (UFBX_INFINITY * 0.0f)
  218. #endif
  219. // -- Platform
  220. #if defined(_MSC_VER)
  221. #define UFBXI_MSC_VER _MSC_VER
  222. #else
  223. #define UFBXI_MSC_VER 0
  224. #endif
  225. #if defined(__GNUC__)
  226. #define UFBXI_GNUC __GNUC__
  227. #else
  228. #define UFBXI_GNUC 0
  229. #endif
  230. #if !defined(UFBX_STANDARD_C) && defined(_MSC_VER)
  231. #define ufbxi_noinline __declspec(noinline)
  232. #define ufbxi_forceinline __forceinline
  233. #define ufbxi_restrict __restrict
  234. #if defined(_Check_return_)
  235. #define ufbxi_nodiscard _Check_return_
  236. #else
  237. #define ufbxi_nodiscard
  238. #endif
  239. #define ufbxi_unused
  240. #define ufbxi_unlikely(cond) (cond)
  241. #elif !defined(UFBX_STANDARD_C) && (defined(__GNUC__) || defined(__clang__))
  242. #define ufbxi_noinline __attribute__((noinline))
  243. #define ufbxi_forceinline inline __attribute__((always_inline))
  244. #define ufbxi_restrict __restrict
  245. #define ufbxi_nodiscard __attribute__((warn_unused_result))
  246. #define ufbxi_unused __attribute__((unused))
  247. #define ufbxi_unlikely(cond) __builtin_expect((cond), 0)
  248. #else
  249. #define ufbxi_noinline
  250. #define ufbxi_forceinline
  251. #define ufbxi_nodiscard
  252. #define ufbxi_restrict
  253. #define ufbxi_unused
  254. #define ufbxi_unlikely(cond) (cond)
  255. #endif
  256. #if !defined(UFBX_STANDARD_C) && defined(__clang__)
  257. #define ufbxi_nounroll _Pragma("clang loop unroll(disable)") _Pragma("clang loop vectorize(disable)")
  258. #elif !defined(UFBX_STANDARD_C) && UFBXI_GNUC >= 8
  259. #define ufbxi_nounroll _Pragma("GCC unroll 0")
  260. #elif !defined(UFBX_STANDARD_C) && defined(_MSC_VER)
  261. #define ufbxi_nounroll __pragma(loop(no_vector))
  262. #else
  263. #define ufbxi_nounroll
  264. #endif
  265. #if defined(__GNUC__) && !defined(__clang__)
  266. #define ufbxi_ignore(cond) (void)!(cond)
  267. #else
  268. #define ufbxi_ignore(cond) (void)(cond)
  269. #endif
  270. #if defined(_MSC_VER)
  271. #pragma warning(push)
  272. #pragma warning(disable: 4061) // enumerator 'ENUM' in switch of enum 'enum' is not explicitly handled by a case label
  273. #pragma warning(disable: 4200) // nonstandard extension used: zero-sized array in struct/union
  274. #pragma warning(disable: 4201) // nonstandard extension used: nameless struct/union
  275. #pragma warning(disable: 4210) // nonstandard extension used: function given file scope
  276. #pragma warning(disable: 4127) // conditional expression is constant
  277. #pragma warning(disable: 4706) // assignment within conditional expression
  278. #pragma warning(disable: 4789) // buffer 'type_and_name' of size 8 bytes will be overrun; 16 bytes will be written starting at offset 0
  279. #pragma warning(disable: 4820) // type': 'N' bytes padding added after data member 'member'
  280. #if defined(UFBX_STANDARD_C)
  281. #pragma warning(disable: 4996) // 'fopen': This function or variable may be unsafe. Consider using fopen_s instead.
  282. #endif
  283. #if defined(UFBXI_PARTIAL_FEATURES)
  284. #pragma warning(disable: 4100) // 'name': unreferenced formal parameter
  285. #pragma warning(disable: 4505) // 'func': unreferenced function with internal linkage has been removed
  286. #endif
  287. #endif
  288. #if defined(__clang__)
  289. #pragma clang diagnostic push
  290. #pragma clang diagnostic ignored "-Wmissing-field-initializers"
  291. #pragma clang diagnostic ignored "-Wmissing-braces"
  292. #pragma clang diagnostic ignored "-Wdouble-promotion"
  293. #pragma clang diagnostic ignored "-Wpedantic"
  294. #pragma clang diagnostic ignored "-Wcast-qual"
  295. #pragma clang diagnostic ignored "-Wcast-align"
  296. #pragma clang diagnostic ignored "-Wcovered-switch-default"
  297. #pragma clang diagnostic ignored "-Wpadded"
  298. #pragma clang diagnostic ignored "-Wswitch-enum"
  299. #pragma clang diagnostic ignored "-Wfloat-equal"
  300. #pragma clang diagnostic ignored "-Wformat-nonliteral"
  301. #if __has_warning("-Watomic-implicit-seq-cst")
  302. #pragma clang diagnostic ignored "-Watomic-implicit-seq-cst"
  303. #endif
  304. #if defined(UFBX_STANDARD_C)
  305. #pragma clang diagnostic ignored "-Wunused-function"
  306. #endif
  307. #if defined(UFBXI_PARTIAL_FEATURES)
  308. #pragma clang diagnostic ignored "-Wunused-function"
  309. #pragma clang diagnostic ignored "-Wunused-parameter"
  310. #endif
  311. #if defined(__cplusplus)
  312. #pragma clang diagnostic ignored "-Wold-style-cast"
  313. #pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
  314. #else
  315. #pragma clang diagnostic ignored "-Wdeclaration-after-statement"
  316. #pragma clang diagnostic ignored "-Wbad-function-cast"
  317. #endif
  318. #endif
  319. #if defined(__GNUC__)
  320. #pragma GCC diagnostic push
  321. #pragma GCC diagnostic ignored "-Wmissing-field-initializers"
  322. #pragma GCC diagnostic ignored "-Wmissing-braces"
  323. #pragma GCC diagnostic ignored "-Wdouble-promotion"
  324. #pragma GCC diagnostic ignored "-Wpedantic"
  325. #pragma GCC diagnostic ignored "-Wcast-qual"
  326. #pragma GCC diagnostic ignored "-Wcast-align"
  327. #pragma GCC diagnostic ignored "-Wpadded"
  328. #pragma GCC diagnostic ignored "-Wswitch-enum"
  329. #pragma GCC diagnostic ignored "-Wfloat-equal"
  330. #pragma GCC diagnostic ignored "-Wformat-nonliteral"
  331. #pragma GCC diagnostic ignored "-Wlong-long"
  332. #if defined(UFBX_STANDARD_C)
  333. #pragma GCC diagnostic ignored "-Wunused-function"
  334. #endif
  335. #if defined(UFBXI_PARTIAL_FEATURES)
  336. #pragma GCC diagnostic ignored "-Wunused-function"
  337. #pragma GCC diagnostic ignored "-Wunused-parameter"
  338. #endif
  339. #if defined(__cplusplus)
  340. #pragma GCC diagnostic ignored "-Wold-style-cast"
  341. #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
  342. #else
  343. #pragma GCC diagnostic ignored "-Wdeclaration-after-statement"
  344. #pragma GCC diagnostic ignored "-Wbad-function-cast"
  345. #if __GNUC__ >= 5
  346. #pragma GCC diagnostic ignored "-Wc90-c99-compat"
  347. #pragma GCC diagnostic ignored "-Wc99-c11-compat"
  348. #endif
  349. #endif
  350. #endif
  351. #if !defined(ufbx_static_assert)
  352. #if defined(__cplusplus) && __cplusplus >= 201103
  353. #define ufbx_static_assert(desc, cond) static_assert(cond, #desc ": " #cond)
  354. #else
  355. #define ufbx_static_assert(desc, cond) typedef char ufbxi_static_assert_##desc[(cond)?1:-1]
  356. #endif
  357. #endif
  358. #if defined(__has_feature)
  359. #if __has_feature(undefined_behavior_sanitizer) && !defined(UFBX_UBSAN)
  360. #define UFBX_UBSAN 1
  361. #endif
  362. #endif
  363. #if defined(__SANITIZE_UNDEFINED__) && !defined(UFBX_UBSAN)
  364. #define UFBX_UBSAN 1
  365. #endif
  366. // Don't use unaligned loads with UB-sanitizer
  367. #if defined(UFBX_UBSAN) && !defined(UFBX_NO_UNALIGNED_LOADS)
  368. #define UFBX_NO_UNALIGNED_LOADS
  369. #endif
  370. #if defined(__clang_analyzer__) && !defined(UFBX_STATIC_ANALYSIS)
  371. #define UFBX_STATIC_ANALYSIS 1
  372. #endif
  373. #if defined(UFBX_STATIC_ANALYSIS)
  374. bool ufbxi_analysis_opaque;
  375. #define ufbxi_maybe_null(ptr) (ufbxi_analysis_opaque ? (ptr) : NULL)
  376. #else
  377. #define ufbxi_maybe_null(ptr) (ptr)
  378. #endif
  379. #if !defined(ufbxi_trace)
  380. #if defined(UFBX_TRACE)
  381. #define ufbxi_trace(desc) (fprintf(stderr, "ufbx trace: %s:%d: %s\n", __FILE__, __LINE__, #desc), fflush(stderr), desc)
  382. #else
  383. #define ufbxi_trace(desc) (desc)
  384. #endif
  385. #endif
  386. #ifndef UFBX_PATH_SEPARATOR
  387. #if defined(_WIN32)
  388. #define UFBX_PATH_SEPARATOR '\\'
  389. #else
  390. #define UFBX_PATH_SEPARATOR '/'
  391. #endif
  392. #endif
  393. #if !defined(UFBX_STANDARD_C) && defined(_POSIX_C_SOURCE)
  394. #if _POSIX_C_SOURCE >= 200112l
  395. #ifndef UFBX_HAS_FTELLO
  396. #define UFBX_HAS_FTELLO
  397. #endif
  398. #endif
  399. #endif
  400. #if !defined(UFBX_STANDARD_C) && (defined(_MSC_VER) && defined(_M_X64)) || ((defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__)) || defined(UFBX_USE_SSE)
  401. #define UFBXI_HAS_SSE 1
  402. #include <xmmintrin.h>
  403. #include <emmintrin.h>
  404. #else
  405. #define UFBXI_HAS_SSE 0
  406. #endif
  407. #if !defined(UFBX_LITTLE_ENDIAN)
  408. #if !defined(UFBX_STANDARD_C) && (defined(_M_IX86) || defined(__i386__) || defined(_M_X64) || defined(__x86_64__) || defined(_M_ARM64) || defined(__aarch64__) || defined(__wasm__) || defined(__EMSCRIPTEN__))
  409. #define UFBX_LITTLE_ENDIAN 1
  410. #else
  411. #define UFBX_LITTLE_ENDIAN 0
  412. #endif
  413. #endif
  414. // Unaligned little-endian load functions
  415. // On platforms that support unaligned access natively (x86, x64, ARM64) just use normal loads,
  416. // with unaligned attributes, otherwise do manual byte-wise load.
  417. #define ufbxi_read_u8(ptr) (*(const uint8_t*)(ptr))
  418. // Detect support for `__attribute__((aligned(1)))`
  419. #if !defined(UFBX_STANDARD_C) && (defined(__clang__) && defined(__APPLE__))
  420. // Apple overrides Clang versioning, 5.0 here maps to 3.3
  421. #if __clang_major__ >= 5
  422. #define UFBXI_HAS_ATTRIBUTE_ALIGNED 1
  423. #endif
  424. #elif !defined(UFBX_STANDARD_C) && defined(__clang__)
  425. #if (__clang_major__ >= 4) || (__clang_major__ == 3 && __clang_minor__ >= 3)
  426. #define UFBXI_HAS_ATTRIBUTE_ALIGNED 1
  427. #endif
  428. #elif !defined(UFBX_STANDARD_C) && defined(__GNUC__)
  429. #if __GNUC__ >= 5
  430. #define UFBXI_HAS_ATTRIBUTE_ALIGNED 1
  431. #endif
  432. #endif
  433. #if defined(UFBXI_HAS_ATTRIBUTE_ALIGNED)
  434. #define UFBXI_HAS_UNALIGNED 1
  435. #define ufbxi_unaligned
  436. typedef uint16_t __attribute__((aligned(1))) ufbxi_unaligned_u16;
  437. typedef uint32_t __attribute__((aligned(1))) ufbxi_unaligned_u32;
  438. typedef uint64_t __attribute__((aligned(1))) ufbxi_unaligned_u64;
  439. typedef float __attribute__((aligned(1))) ufbxi_unaligned_f32;
  440. typedef double __attribute__((aligned(1))) ufbxi_unaligned_f64;
  441. #elif !defined(UFBX_STANDARD_C) && defined(_MSC_VER)
  442. #define UFBXI_HAS_UNALIGNED 1
  443. #if defined(_M_IX86)
  444. // MSVC seems to assume all pointers are unaligned for x86
  445. #define ufbxi_unaligned
  446. #else
  447. #define ufbxi_unaligned __unaligned
  448. #endif
  449. typedef uint16_t ufbxi_unaligned_u16;
  450. typedef uint32_t ufbxi_unaligned_u32;
  451. typedef uint64_t ufbxi_unaligned_u64;
  452. typedef float ufbxi_unaligned_f32;
  453. typedef double ufbxi_unaligned_f64;
  454. #endif
  455. #if (defined(UFBXI_HAS_UNALIGNED) && UFBX_LITTLE_ENDIAN && !defined(UFBX_NO_UNALIGNED_LOADS)) || defined(UFBX_USE_UNALIGNED_LOADS)
  456. #define ufbxi_read_u16(ptr) (*(const ufbxi_unaligned ufbxi_unaligned_u16*)(ptr))
  457. #define ufbxi_read_u32(ptr) (*(const ufbxi_unaligned ufbxi_unaligned_u32*)(ptr))
  458. #define ufbxi_read_u64(ptr) (*(const ufbxi_unaligned ufbxi_unaligned_u64*)(ptr))
  459. #define ufbxi_read_f32(ptr) (*(const ufbxi_unaligned ufbxi_unaligned_f32*)(ptr))
  460. #define ufbxi_read_f64(ptr) (*(const ufbxi_unaligned ufbxi_unaligned_f64*)(ptr))
  461. #else
  462. static ufbxi_forceinline uint16_t ufbxi_read_u16(const void *ptr) {
  463. const char *p = (const char*)ptr;
  464. return (uint16_t)(
  465. (unsigned)(uint8_t)p[0] << 0u |
  466. (unsigned)(uint8_t)p[1] << 8u );
  467. }
  468. static ufbxi_forceinline uint32_t ufbxi_read_u32(const void *ptr) {
  469. const char *p = (const char*)ptr;
  470. return (uint32_t)(
  471. (unsigned)(uint8_t)p[0] << 0u |
  472. (unsigned)(uint8_t)p[1] << 8u |
  473. (unsigned)(uint8_t)p[2] << 16u |
  474. (unsigned)(uint8_t)p[3] << 24u );
  475. }
  476. static ufbxi_forceinline uint64_t ufbxi_read_u64(const void *ptr) {
  477. const char *p = (const char*)ptr;
  478. return (uint64_t)(
  479. (uint64_t)(uint8_t)p[0] << 0u |
  480. (uint64_t)(uint8_t)p[1] << 8u |
  481. (uint64_t)(uint8_t)p[2] << 16u |
  482. (uint64_t)(uint8_t)p[3] << 24u |
  483. (uint64_t)(uint8_t)p[4] << 32u |
  484. (uint64_t)(uint8_t)p[5] << 40u |
  485. (uint64_t)(uint8_t)p[6] << 48u |
  486. (uint64_t)(uint8_t)p[7] << 56u );
  487. }
  488. static ufbxi_forceinline float ufbxi_read_f32(const void *ptr) {
  489. uint32_t u = ufbxi_read_u32(ptr);
  490. float f;
  491. memcpy(&f, &u, 4);
  492. return f;
  493. }
  494. static ufbxi_forceinline double ufbxi_read_f64(const void *ptr) {
  495. uint64_t u = ufbxi_read_u64(ptr);
  496. double f;
  497. memcpy(&f, &u, 8);
  498. return f;
  499. }
  500. #endif
  501. #define ufbxi_read_i8(ptr) (int8_t)(ufbxi_read_u8(ptr))
  502. #define ufbxi_read_i16(ptr) (int16_t)(ufbxi_read_u16(ptr))
  503. #define ufbxi_read_i32(ptr) (int32_t)(ufbxi_read_u32(ptr))
  504. #define ufbxi_read_i64(ptr) (int64_t)(ufbxi_read_u64(ptr))
  505. ufbx_static_assert(sizeof_bool, sizeof(bool) == 1);
  506. ufbx_static_assert(sizeof_char, sizeof(char) == 1);
  507. ufbx_static_assert(sizeof_i8, sizeof(int8_t) == 1);
  508. ufbx_static_assert(sizeof_i16, sizeof(int16_t) == 2);
  509. ufbx_static_assert(sizeof_i32, sizeof(int32_t) == 4);
  510. ufbx_static_assert(sizeof_i64, sizeof(int64_t) == 8);
  511. ufbx_static_assert(sizeof_u8, sizeof(uint8_t) == 1);
  512. ufbx_static_assert(sizeof_u16, sizeof(uint16_t) == 2);
  513. ufbx_static_assert(sizeof_u32, sizeof(uint32_t) == 4);
  514. ufbx_static_assert(sizeof_u64, sizeof(uint64_t) == 8);
  515. ufbx_static_assert(sizeof_f32, sizeof(float) == 4);
  516. ufbx_static_assert(sizeof_f64, sizeof(double) == 8);
  517. // -- Version
  518. #define UFBX_SOURCE_VERSION ufbx_pack_version(0, 14, 0)
  519. ufbx_abi_data_def const uint32_t ufbx_source_version = UFBX_SOURCE_VERSION;
  520. ufbx_static_assert(source_header_version, UFBX_SOURCE_VERSION/1000u == UFBX_HEADER_VERSION/1000u);
  521. // -- Fast copy
  522. #if UFBXI_HAS_SSE
  523. #define ufbxi_copy_16_bytes(dst, src) _mm_storeu_si128((__m128i*)(dst), _mm_loadu_si128((const __m128i*)(src)))
  524. #elif defined(UFBXI_HAS_UNALIGNED)
  525. #define ufbxi_copy_16_bytes(dst, src) do { \
  526. ufbxi_unaligned ufbxi_unaligned_u64 *mi_dst = (ufbxi_unaligned ufbxi_unaligned_u64 *)(dst); \
  527. const ufbxi_unaligned ufbxi_unaligned_u64 *mi_src = (const ufbxi_unaligned ufbxi_unaligned_u64 *)src; \
  528. mi_dst[0] = mi_src[0]; \
  529. mi_dst[1] = mi_src[1]; \
  530. } while (0)
  531. #else
  532. #define ufbxi_copy_16_bytes(dst, src) memcpy((dst), (src), 16)
  533. #endif
  534. // -- Large fast integer
  535. #if !defined(UFBX_STANDARD_C) && (defined(__wasm__) || defined(__EMSCRIPTEN__)) && !defined(UFBX_WASM_32BIT)
  536. typedef uint64_t ufbxi_fast_uint;
  537. #else
  538. typedef size_t ufbxi_fast_uint;
  539. #endif
  540. // -- Wrapping right shift
  541. #if !defined(UFBX_STANDARD_C) && defined(_MSC_VER) && defined(_M_X64)
  542. #define ufbxi_wrap_shr64(a, b) ((a) >> (b))
  543. #else
  544. #define ufbxi_wrap_shr64(a, b) ((a) >> ((b) & 63))
  545. #endif
  546. // -- Atomic counter
  547. #define UFBXI_THREAD_SAFE 1
  548. #if defined(__cplusplus)
  549. #define ufbxi_extern_c extern "C"
  550. #else
  551. #define ufbxi_extern_c
  552. #endif
  553. #if !defined(UFBX_STANDARD_C) && (defined(__GNUC__) || defined(__clang__) || defined(__INTEL_COMPILER))
  554. typedef size_t ufbxi_atomic_counter;
  555. #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0)
  556. #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0)
  557. #define ufbxi_atomic_counter_inc(ptr) __sync_fetch_and_add((ptr), 1)
  558. #define ufbxi_atomic_counter_dec(ptr) __sync_fetch_and_sub((ptr), 1)
  559. #define ufbxi_atomic_counter_load(ptr) __sync_fetch_and_add((ptr), 0) // TODO: Proper atomic load
  560. #elif !defined(UFBX_STANDARD_C) && defined(_MSC_VER)
  561. #if defined(_M_X64) || defined(_M_ARM64)
  562. ufbxi_extern_c __int64 _InterlockedIncrement64(__int64 volatile * lpAddend);
  563. ufbxi_extern_c __int64 _InterlockedDecrement64(__int64 volatile * lpAddend);
  564. ufbxi_extern_c __int64 _InterlockedExchangeAdd64(__int64 volatile * lpAddend, __int64 Value);
  565. typedef volatile __int64 ufbxi_atomic_counter;
  566. #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0)
  567. #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0)
  568. #define ufbxi_atomic_counter_inc(ptr) ((size_t)_InterlockedIncrement64(ptr) - 1)
  569. #define ufbxi_atomic_counter_dec(ptr) ((size_t)_InterlockedDecrement64(ptr) + 1)
  570. #define ufbxi_atomic_counter_load(ptr) ((size_t)_InterlockedExchangeAdd64((ptr), 0))
  571. #else
  572. ufbxi_extern_c long __cdecl _InterlockedIncrement(long volatile * lpAddend);
  573. ufbxi_extern_c long __cdecl _InterlockedDecrement(long volatile * lpAddend);
  574. ufbxi_extern_c long __cdecl _InterlockedExchangeAdd(long volatile * lpAddend, long Value);
  575. typedef volatile long ufbxi_atomic_counter;
  576. #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0)
  577. #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0)
  578. #define ufbxi_atomic_counter_inc(ptr) ((size_t)_InterlockedIncrement(ptr) - 1)
  579. #define ufbxi_atomic_counter_dec(ptr) ((size_t)_InterlockedDecrement(ptr) + 1)
  580. #define ufbxi_atomic_counter_load(ptr) ((size_t)_InterlockedExchangeAdd((ptr), 0))
  581. #endif
  582. #elif !defined(UFBX_STANDARD_C) && defined(__TINYC__)
  583. #if defined(__x86_64__) || defined(_AMD64_)
  584. static size_t ufbxi_tcc_atomic_add(volatile size_t *dst, size_t value) {
  585. __asm__ __volatile__("lock; xaddq %0, %1;" : "+r" (value), "=m" (*dst) : "m" (dst));
  586. return value;
  587. }
  588. #elif defined(__i386__) || defined(_X86_)
  589. static size_t ufbxi_tcc_atomic_add(volatile size_t *dst, size_t value) {
  590. __asm__ __volatile__("lock; xaddl %0, %1;" : "+r" (value), "=m" (*dst) : "m" (dst));
  591. return value;
  592. }
  593. #else
  594. #error Unexpected TCC architecture
  595. #endif
  596. typedef volatile size_t ufbxi_atomic_counter;
  597. #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0)
  598. #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0)
  599. #define ufbxi_atomic_counter_inc(ptr) ufbxi_tcc_atomic_add((ptr), 1)
  600. #define ufbxi_atomic_counter_dec(ptr) ufbxi_tcc_atomic_add((ptr), SIZE_MAX)
  601. #define ufbxi_atomic_counter_load(ptr) ufbxi_tcc_atomic_add((ptr), 0)
  602. #elif defined(__cplusplus) && (__cplusplus >= 201103L)
  603. #include <new>
  604. #include <atomic>
  605. typedef struct { alignas(std::atomic_size_t) char data[sizeof(std::atomic_size_t)]; } ufbxi_atomic_counter;
  606. #define ufbxi_atomic_counter_init(ptr) (new (&(ptr)->data) std::atomic_size_t(0))
  607. #define ufbxi_atomic_counter_free(ptr) (((std::atomic_size_t*)(ptr)->data)->~atomic())
  608. #define ufbxi_atomic_counter_inc(ptr) ((std::atomic_size_t*)(ptr)->data)->fetch_add(1)
  609. #define ufbxi_atomic_counter_dec(ptr) ((std::atomic_size_t*)(ptr)->data)->fetch_sub(1)
  610. #define ufbxi_atomic_counter_load(ptr) ((std::atomic_size_t*)(ptr)->data)->load(std::memory_order_acquire)
  611. #elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(__STDC_NO_ATOMICS__)
  612. #include <stdatomic.h>
  613. typedef volatile atomic_size_t ufbxi_atomic_counter;
  614. #define ufbxi_atomic_counter_init(ptr) atomic_init(ptr, 0)
  615. #define ufbxi_atomic_counter_free(ptr) (void)(ptr)
  616. #define ufbxi_atomic_counter_inc(ptr) atomic_fetch_add((ptr), 1)
  617. #define ufbxi_atomic_counter_dec(ptr) atomic_fetch_sub((ptr), 1)
  618. #define ufbxi_atomic_counter_load(ptr) atomic_load_explicit((ptr), memory_order_acquire)
  619. #else
  620. typedef volatile size_t ufbxi_atomic_counter;
  621. #define ufbxi_atomic_counter_init(ptr) (*(ptr) = 0)
  622. #define ufbxi_atomic_counter_free(ptr) (*(ptr) = 0)
  623. #define ufbxi_atomic_counter_inc(ptr) ((*(ptr))++)
  624. #define ufbxi_atomic_counter_dec(ptr) ((*(ptr))--)
  625. #define ufbxi_atomic_counter_load(ptr) (*(ptr))
  626. #undef UFBXI_THREAD_SAFE
  627. #define UFBXI_THREAD_SAFE 0
  628. #endif
  629. // -- Bit manipulation
  630. #if !defined(UFBX_STANDARD_C) && defined(_MSC_VER) && (defined(_M_X64) || defined(_M_IX86))
  631. ufbxi_extern_c unsigned char _BitScanReverse(unsigned long * _Index, unsigned long _Mask);
  632. ufbxi_extern_c unsigned char _BitScanReverse64(unsigned long * _Index, unsigned __int64 _Mask);
  633. static ufbxi_forceinline ufbxi_unused uint32_t ufbxi_lzcnt64(uint64_t v) {
  634. unsigned long index;
  635. #if defined(_M_X64)
  636. _BitScanReverse64(&index, (unsigned __int64)v);
  637. #else
  638. uint32_t hi = (uint32_t)(v >> 32u);
  639. uint32_t hi_nonzero = hi != 0 ? 1 : 0;
  640. uint32_t part = hi_nonzero ? hi : (uint32_t)v;
  641. _BitScanReverse(&index, (unsigned long)part);
  642. index += hi_nonzero * 32u;
  643. #endif
  644. return 63 - (uint32_t)index;
  645. }
  646. #elif !defined(UFBX_STANDARD_C) && (defined(__GNUC__) || defined(__clang__))
  647. #define ufbxi_lzcnt64(v) ((uint32_t)__builtin_clzll((unsigned long long)(v)))
  648. #else
  649. // DeBrujin table lookup
  650. static const uint8_t ufbxi_lzcnt_table[] = {
  651. 63, 16, 62, 7, 15, 36, 61, 3, 6, 14, 22, 26, 35, 47, 60, 2, 9, 5, 28, 11, 13, 21, 42,
  652. 19, 25, 31, 34, 40, 46, 52, 59, 1, 17, 8, 37, 4, 23, 27, 48, 10, 29, 12, 43, 20, 32, 41,
  653. 53, 18, 38, 24, 49, 30, 44, 33, 54, 39, 50, 45, 55, 51, 56, 57, 58, 0,
  654. };
  655. static ufbxi_noinline ufbxi_unused uint32_t ufbxi_lzcnt64(uint64_t v) {
  656. v |= v >> 1;
  657. v |= v >> 2;
  658. v |= v >> 4;
  659. v |= v >> 8;
  660. v |= v >> 16;
  661. v |= v >> 32;
  662. return ufbxi_lzcnt_table[(v * UINT64_C(0x03f79d71b4cb0a89)) >> 58];
  663. }
  664. #endif
  665. // -- Debug
  666. #if defined(UFBX_DEBUG_BINARY_SEARCH) || defined(UFBX_REGRESSION)
  667. #define ufbxi_clamp_linear_threshold(v) (2)
  668. #else
  669. #define ufbxi_clamp_linear_threshold(v) (v)
  670. #endif
  671. #if defined(UFBX_REGRESSION)
  672. #undef UFBXI_MAX_SKIP_SIZE
  673. #define UFBXI_MAX_SKIP_SIZE 128
  674. #undef UFBXI_MAP_MAX_SCAN
  675. #define UFBXI_MAP_MAX_SCAN 2
  676. #undef UFBXI_KD_FAST_DEPTH
  677. #define UFBXI_KD_FAST_DEPTH 2
  678. #undef UFBXI_FACE_GROUP_HASH_BITS
  679. #define UFBXI_FACE_GROUP_HASH_BITS 2
  680. #endif
  681. #if defined(UFBX_REGRESSION) || defined(UFBX_EXTENSIVE_THREADING)
  682. #undef UFBXI_MIN_THREADED_DEFLATE_BYTES
  683. #define UFBXI_MIN_THREADED_DEFLATE_BYTES 2
  684. #undef UFBXI_MIN_THREADED_ASCII_VALUES
  685. #define UFBXI_MIN_THREADED_ASCII_VALUES 2
  686. #endif
  687. #if defined(UFBX_REGRESSION)
  688. #define ufbxi_regression_assert(cond) ufbx_assert(cond)
  689. #else
  690. #define ufbxi_regression_assert(cond) (void)0
  691. #endif
  692. #if defined(UFBX_REGRESSION) || defined(UFBX_DEV)
  693. #define ufbxi_dev_assert(cond) ufbx_assert(cond)
  694. #else
  695. #define ufbxi_dev_assert(cond) (void)0
  696. #endif
  697. #define ufbxi_unreachable(reason) do { ufbx_assert(0 && reason); } while (0)
  698. #if defined(UFBX_REGRESSION)
  699. #define UFBXI_IS_REGRESSION 1
  700. #else
  701. #define UFBXI_IS_REGRESSION 0
  702. #endif
  703. #if defined(_MSC_VER)
  704. #define ufbxi_thread_local __declspec(thread)
  705. #elif defined(__GNUC__) || defined(__clang__)
  706. #define ufbxi_thread_local __thread
  707. #elif UFBXI_HAS_CPP11
  708. #define ufbxi_thread_local thread_local
  709. #elif UFBX_STDC >= 201112L
  710. #define ufbxi_thread_local _Thread_local
  711. #endif
  712. #if defined(UFBXI_ANALYSIS_RECURSIVE)
  713. #define ufbxi_recursive_function(m_ret, m_name, m_args, m_max_depth, m_params) UFBXI_RECURSIVE_FUNCTION(m_name, m_max_depth);
  714. #define ufbxi_recursive_function_void(m_name, m_args, m_max_depth, m_params) UFBXI_RECURSIVE_FUNCTION(m_name, m_max_depth);
  715. #elif UFBXI_IS_REGRESSION && defined(ufbxi_thread_local)
  716. #define ufbxi_recursive_function(m_ret, m_name, m_args, m_max_depth, m_params) \
  717. { \
  718. m_ret m_name##_rec m_params; \
  719. static ufbxi_thread_local unsigned ufbxi_recursion_depth; \
  720. ufbx_assert(ufbxi_recursion_depth < m_max_depth); \
  721. ++ufbxi_recursion_depth; \
  722. m_ret ret = m_name##_rec m_args; \
  723. --ufbxi_recursion_depth; \
  724. return ret; \
  725. } \
  726. m_ret m_name##_rec m_params
  727. #define ufbxi_recursive_function_void(m_name, m_args, m_max_depth, m_params) \
  728. { \
  729. void m_name##_rec m_params; \
  730. static ufbxi_thread_local unsigned ufbxi_recursion_depth; \
  731. ufbx_assert(ufbxi_recursion_depth < m_max_depth); \
  732. ++ufbxi_recursion_depth; \
  733. m_name##_rec m_args; \
  734. --ufbxi_recursion_depth; \
  735. } \
  736. void m_name##_rec m_params
  737. #else
  738. #define ufbxi_recursive_function(m_ret, m_name, m_args, m_max_depth, m_params)
  739. #define ufbxi_recursive_function_void(m_name, m_args, m_max_depth, m_params)
  740. #endif
  741. // -- Utility
  742. #if defined(UFBX_UBSAN)
  743. static void ufbxi_assert_zero(size_t offset) { ufbx_assert(offset == 0); }
  744. #define ufbxi_add_ptr(ptr, offset) ((ptr) ? (ptr) + (offset) : (ufbxi_assert_zero((size_t)(offset)), (ptr)))
  745. #define ufbxi_sub_ptr(ptr, offset) ((ptr) ? (ptr) - (offset) : (ufbxi_assert_zero((size_t)(offset)), (ptr)))
  746. #else
  747. #define ufbxi_add_ptr(ptr, offset) ((ptr) + (offset))
  748. #define ufbxi_sub_ptr(ptr, offset) ((ptr) - (offset))
  749. #endif
  750. #define ufbxi_arraycount(arr) (sizeof(arr) / sizeof(*(arr)))
  751. #define ufbxi_for(m_type, m_name, m_begin, m_num) for (m_type *m_name = m_begin, *m_name##_end = ufbxi_add_ptr(m_name, m_num); m_name != m_name##_end; m_name++)
  752. #define ufbxi_for_ptr(m_type, m_name, m_begin, m_num) for (m_type **m_name = m_begin, **m_name##_end = ufbxi_add_ptr(m_name, m_num); m_name != m_name##_end; m_name++)
  753. // WARNING: Evaluates `m_list` twice!
  754. #define ufbxi_for_list(m_type, m_name, m_list) for (m_type *m_name = (m_list).data, *m_name##_end = ufbxi_add_ptr(m_name, (m_list).count); m_name != m_name##_end; m_name++)
  755. #define ufbxi_for_ptr_list(m_type, m_name, m_list) for (m_type **m_name = (m_list).data, **m_name##_end = ufbxi_add_ptr(m_name, (m_list).count); m_name != m_name##_end; m_name++)
  756. #define ufbxi_string_literal(str) { str, sizeof(str) - 1 }
  757. static ufbxi_forceinline uint32_t ufbxi_min32(uint32_t a, uint32_t b) { return a < b ? a : b; }
  758. static ufbxi_forceinline uint32_t ufbxi_max32(uint32_t a, uint32_t b) { return a < b ? b : a; }
  759. static ufbxi_forceinline uint64_t ufbxi_min64(uint64_t a, uint64_t b) { return a < b ? a : b; }
  760. static ufbxi_forceinline uint64_t ufbxi_max64(uint64_t a, uint64_t b) { return a < b ? b : a; }
  761. static ufbxi_forceinline size_t ufbxi_min_sz(size_t a, size_t b) { return a < b ? a : b; }
  762. static ufbxi_forceinline size_t ufbxi_max_sz(size_t a, size_t b) { return a < b ? b : a; }
  763. static ufbxi_forceinline ufbx_real ufbxi_min_real(ufbx_real a, ufbx_real b) { return a < b ? a : b; }
  764. static ufbxi_forceinline ufbx_real ufbxi_max_real(ufbx_real a, ufbx_real b) { return a < b ? b : a; }
  765. static ufbxi_forceinline int32_t ufbxi_f64_to_i32(double value)
  766. {
  767. if (ufbx_fabs(value) <= (double)INT32_MAX) {
  768. return (int32_t)value;
  769. } else {
  770. return value >= 0.0 ? INT32_MAX : INT32_MIN;
  771. }
  772. }
  773. static ufbxi_forceinline int64_t ufbxi_f64_to_i64(double value)
  774. {
  775. if (ufbx_fabs(value) <= (double)INT64_MAX) {
  776. return (int64_t)value;
  777. } else {
  778. return value >= 0.0 ? INT64_MAX : INT64_MIN;
  779. }
  780. }
  781. #if defined(UFBX_REGRESSION)
  782. static size_t ufbxi_to_size(ptrdiff_t delta) {
  783. ufbx_assert(delta >= 0);
  784. return (size_t)delta;
  785. }
  786. #else
  787. #define ufbxi_to_size(delta) ((size_t)(delta))
  788. #endif
  789. // Stable sort array `m_type m_data[m_size]` using the predicate `m_cmp_lambda(a, b)`
  790. // `m_linear_size` is a hint for how large blocks handle initially do with insertion sort
  791. // `m_tmp` must be a memory buffer with at least the same size and alignment as `m_data`
  792. #define ufbxi_macro_stable_sort(m_type, m_linear_size, m_data, m_tmp, m_size, m_cmp_lambda) do { \
  793. typedef m_type mi_type; \
  794. mi_type *mi_src = (mi_type*)(m_tmp); \
  795. mi_type *mi_data = m_data, *mi_dst = mi_data; \
  796. size_t mi_block_size = ufbxi_clamp_linear_threshold(m_linear_size), mi_size = m_size; \
  797. /* Insertion sort in `m_linear_size` blocks */ \
  798. for (size_t mi_base = 0; mi_base < mi_size; mi_base += mi_block_size) { \
  799. size_t mi_i_end = mi_base + mi_block_size; \
  800. if (mi_i_end > mi_size) mi_i_end = mi_size; \
  801. for (size_t mi_i = mi_base + 1; mi_i < mi_i_end; mi_i++) { \
  802. size_t mi_j = mi_i; \
  803. mi_src[0] = mi_dst[mi_i]; \
  804. for (; mi_j != mi_base; --mi_j) { \
  805. mi_type *a = &mi_src[0], *b = &mi_dst[mi_j - 1]; \
  806. if (!( m_cmp_lambda )) break; \
  807. mi_dst[mi_j] = mi_dst[mi_j - 1]; \
  808. } \
  809. mi_dst[mi_j] = mi_src[0]; \
  810. } \
  811. } \
  812. /* Merge sort ping-ponging between `m_data` and `m_tmp` */ \
  813. for (; mi_block_size < mi_size; mi_block_size *= 2) { \
  814. mi_type *mi_swap = mi_dst; mi_dst = mi_src; mi_src = mi_swap; \
  815. for (size_t mi_base = 0; mi_base < mi_size; mi_base += mi_block_size * 2) { \
  816. size_t mi_i = mi_base, mi_i_end = mi_base + mi_block_size; \
  817. size_t mi_j = mi_i_end, mi_j_end = mi_j + mi_block_size; \
  818. size_t mi_k = mi_base; \
  819. if (mi_i_end > mi_size) mi_i_end = mi_size; \
  820. if (mi_j_end > mi_size) mi_j_end = mi_size; \
  821. while ((mi_i < mi_i_end) & (mi_j < mi_j_end)) { \
  822. mi_type *a = &mi_src[mi_j], *b = &mi_src[mi_i]; \
  823. if ( m_cmp_lambda ) { \
  824. mi_dst[mi_k] = *a; mi_j++; \
  825. } else { \
  826. mi_dst[mi_k] = *b; mi_i++; \
  827. } \
  828. mi_k++; \
  829. } \
  830. while (mi_i < mi_i_end) mi_dst[mi_k++] = mi_src[mi_i++]; \
  831. while (mi_j < mi_j_end) mi_dst[mi_k++] = mi_src[mi_j++]; \
  832. } \
  833. } \
  834. /* Copy the result to `m_data` if we ended up in `m_tmp` */ \
  835. if (mi_dst != mi_data) memcpy((void*)mi_data, mi_dst, sizeof(mi_type) * mi_size); \
  836. } while (0)
  837. #define ufbxi_macro_lower_bound_eq(m_type, m_linear_size, m_result_ptr, m_data, m_begin, m_size, m_cmp_lambda, m_eq_lambda) do { \
  838. typedef m_type mi_type; \
  839. const mi_type *mi_data = (m_data); \
  840. size_t mi_lo = m_begin, mi_hi = m_size, mi_linear_size = ufbxi_clamp_linear_threshold(m_linear_size); \
  841. ufbx_assert(mi_linear_size > 1); \
  842. /* Binary search until we get down to `m_linear_size` elements */ \
  843. while (mi_hi - mi_lo > mi_linear_size) { \
  844. size_t mi_mid = mi_lo + (mi_hi - mi_lo) / 2; \
  845. const mi_type *a = &mi_data[mi_mid]; \
  846. if ( m_cmp_lambda ) { mi_lo = mi_mid + 1; } else { mi_hi = mi_mid + 1; } \
  847. } \
  848. /* Linearly scan until we find the edge */ \
  849. for (; mi_lo < mi_hi; mi_lo++) { \
  850. const mi_type *a = &mi_data[mi_lo]; \
  851. if ( m_eq_lambda ) { *(m_result_ptr) = mi_lo; break; } \
  852. } \
  853. } while (0)
  854. #define ufbxi_macro_upper_bound_eq(m_type, m_linear_size, m_result_ptr, m_data, m_begin, m_size, m_eq_lambda) do { \
  855. typedef m_type mi_type; \
  856. const mi_type *mi_data = (m_data); \
  857. size_t mi_lo = m_begin, mi_hi = m_size, mi_linear_size = ufbxi_clamp_linear_threshold(m_linear_size); \
  858. ufbx_assert(mi_linear_size > 1); \
  859. /* Linearly scan with galloping */ \
  860. for (size_t mi_step = 1; mi_step < 100 && mi_hi - mi_lo > mi_step; mi_step *= 2) { \
  861. const mi_type *a = &mi_data[mi_lo + mi_step]; \
  862. if (!( m_eq_lambda )) { mi_hi = mi_lo + mi_step; break; } \
  863. mi_lo += mi_step; \
  864. } \
  865. /* Binary search until we get down to `m_linear_size` elements */ \
  866. while (mi_hi - mi_lo > mi_linear_size) { \
  867. size_t mi_mid = mi_lo + (mi_hi - mi_lo) / 2; \
  868. const mi_type *a = &mi_data[mi_mid]; \
  869. if ( m_eq_lambda ) { mi_lo = mi_mid + 1; } else { mi_hi = mi_mid + 1; } \
  870. } \
  871. /* Linearly scan until we find the edge */ \
  872. for (; mi_lo < mi_hi; mi_lo++) { \
  873. const mi_type *a = &mi_data[mi_lo]; \
  874. if (!( m_eq_lambda )) break; \
  875. } \
  876. *(m_result_ptr) = mi_lo; \
  877. } while (0)
  878. typedef bool ufbxi_less_fn(void *user, const void *a, const void *b);
  879. static ufbxi_noinline void ufbxi_stable_sort(size_t stride, size_t linear_size, void *in_data, void *in_tmp, size_t size, ufbxi_less_fn *less_fn, void *less_user)
  880. {
  881. (void)linear_size;
  882. char *src = (char*)in_tmp;
  883. char *data = (char*)in_data, *dst = (char*)data;
  884. size_t block_size = ufbxi_clamp_linear_threshold(linear_size);
  885. /* Insertion sort in `linear_size` blocks */
  886. for (size_t base = 0; base < size; base += block_size) {
  887. size_t i_end = base + block_size;
  888. if (i_end > size) i_end = size;
  889. for (size_t i = base + 1; i < i_end; i++) {
  890. {
  891. char *a = dst + i * stride, *b = dst + (i - 1) * stride;
  892. if (!less_fn(less_user, a, b)) continue;
  893. }
  894. size_t j = i - 1;
  895. memcpy(src, dst + i * stride, stride);
  896. memcpy(dst + i * stride, dst + j * stride, stride);
  897. for (; j != base; --j) {
  898. char *a = src, *b = dst + (j - 1) * stride;
  899. if (!less_fn(less_user, a, b)) break;
  900. memcpy(dst + j * stride, dst + (j - 1) * stride, stride);
  901. }
  902. memcpy(dst + j * stride, src, stride);
  903. }
  904. }
  905. /* Merge sort ping-ponging between `data` and `tmp` */
  906. for (; block_size < size; block_size *= 2) {
  907. char *swap = dst; dst = src; src = swap;
  908. for (size_t base = 0; base < size; base += block_size * 2) {
  909. size_t i = base, i_end = base + block_size;
  910. size_t j = i_end, j_end = j + block_size;
  911. size_t k = base;
  912. if (i_end > size) i_end = size;
  913. if (j_end > size) j_end = size;
  914. while ((i < i_end) & (j < j_end)) {
  915. char *a = src + j * stride, *b = src + i * stride;
  916. if (less_fn(less_user, a, b)) {
  917. memcpy(dst + k * stride, a, stride);
  918. j++;
  919. } else {
  920. memcpy(dst + k * stride, b, stride);
  921. i++;
  922. }
  923. k++;
  924. }
  925. memcpy(dst + k * stride, src + i * stride, (i_end - i) * stride);
  926. if (j < j_end) {
  927. memcpy(dst + (k + (i_end - i)) * stride, src + j * stride, (j_end - j) * stride);
  928. }
  929. }
  930. }
  931. /* Copy the result to `data` if we ended up in `tmp` */
  932. if (dst != data) memcpy((void*)data, dst, size * stride);
  933. }
  934. static ufbxi_forceinline void ufbxi_swap(void *a, void *b, size_t size)
  935. {
  936. char *ca = (char*)a, *cb = (char*)b;
  937. #if defined(UFBXI_HAS_UNALIGNED)
  938. ufbxi_nounroll while (size >= 4) {
  939. uint32_t t = *(ufbxi_unaligned ufbxi_unaligned_u32*)ca;
  940. *(ufbxi_unaligned ufbxi_unaligned_u32*)ca = *(ufbxi_unaligned ufbxi_unaligned_u32*)cb;
  941. *(ufbxi_unaligned ufbxi_unaligned_u32*)cb = t;
  942. ca += 4; cb += 4; size -= 4;
  943. }
  944. #endif
  945. ufbxi_nounroll while (size > 0) {
  946. char t = *ca; *ca = *cb; *cb = t;
  947. ca++; cb++; size--;
  948. }
  949. }
  950. static ufbxi_noinline void ufbxi_unstable_sort(void *in_data, size_t size, size_t stride, ufbxi_less_fn *less_fn, void *less_user)
  951. {
  952. if (size <= 1) return;
  953. char *data = (char*)in_data;
  954. size_t start = (size - 1) >> 1;
  955. size_t end = size - 1;
  956. for (;;) {
  957. size_t root = start;
  958. size_t child;
  959. while ((child = root*2 + 1) <= end) {
  960. size_t next = less_fn(less_user, data + child * stride, data + root * stride) ? root : child;
  961. if (child + 1 <= end && less_fn(less_user, data + next * stride, data + (child + 1) * stride)) {
  962. next = child + 1;
  963. }
  964. if (next == root) break;
  965. ufbxi_swap(data + root * stride, data + next * stride, stride);
  966. root = next;
  967. }
  968. if (start > 0) {
  969. start--;
  970. } else if (end > 0) {
  971. ufbxi_swap(data + end * stride, data, stride);
  972. end--;
  973. } else {
  974. break;
  975. }
  976. }
  977. }
  978. // -- Float parsing
  979. //
  980. // Custom float parsing that handles floats up to (-)ddddddddddddddddddd.ddddddddddddddddddd
  981. // If larger or scientific notation is used then it defers to `strtod()`.
  982. // For the algorithm we need 128-bit division that is either provided by hardware on x64 or
  983. // a custom implementation below.
  984. #if !defined(UFBX_STANDARD_C) && UFBXI_MSC_VER >= 1920 && defined(_M_X64) && !defined(__clang__)
  985. ufbxi_extern_c extern unsigned __int64 __cdecl _udiv128(unsigned __int64 highdividend,
  986. unsigned __int64 lowdividend, unsigned __int64 divisor, unsigned __int64 *remainder);
  987. #define ufbxi_div128(a_hi, a_lo, b, p_rem) (_udiv128((a_hi), (a_lo), (b), (p_rem)))
  988. #elif !defined(UFBX_STANDARD_C) && (defined(__GNUC__) || defined(__clang__)) && (defined(__x86_64__) || defined(_M_X64))
  989. static ufbxi_forceinline uint64_t ufbxi_div128(uint64_t a_hi, uint64_t a_lo, uint64_t b, uint64_t *p_rem) {
  990. uint64_t quot, rem;
  991. __asm__("divq %[v]" : "=a"(quot), "=d"(rem) : [v] "r"(b), "a"(a_lo), "d"(a_hi));
  992. *p_rem = rem;
  993. return quot;
  994. }
  995. #else
  996. static ufbxi_forceinline uint64_t ufbxi_div128(uint64_t a_hi, uint64_t a_lo, uint64_t b, uint64_t *p_rem) {
  997. // Divide `(a_hi << 64 | a_lo)` by `b`, returns quotinent and stores reminder in `p_rem`.
  998. // Based on TAOCP 2.4 multi-word division single algorithm digit step.
  999. //
  1000. // Notation:
  1001. // b is the base (2^32) in this case
  1002. // aN is the Nth digit (base b) of a from the least significant digit
  1003. // { x y z } is a multi-digit number b^2*x + b*y + z
  1004. // ie. for a 64-bit number a = { a1 a0 } = b*a1 + a0
  1005. //
  1006. // We do the division in two steps by dividing three digits in each iteration:
  1007. //
  1008. // q1, r = { a3 a2 a1 } / { b1 b0 }
  1009. // q0, r = { r1 r0 a0 } / { b1 b0 }
  1010. //
  1011. // In each step we want to compute the expression:
  1012. //
  1013. // q, r = { u2 u1 u0 } / { v1 v0 }
  1014. //
  1015. // However we cannot rely on being able to do `u96 / u64` division we estimate
  1016. // the result by considering only the leading digits:
  1017. //
  1018. // q^ = { u2 u1 } / v1 [A]
  1019. // r^ = { u2 u1 } % v1 = { u2 u1 } - v1 * q^ [B]
  1020. //
  1021. // As long as `v1 >= b/2` the estimate `q^` is at most two larger than the actual `q`
  1022. // (proof in TAOCP 2.4) so we can compute the correction amount `c`:
  1023. //
  1024. // q <= q^ <= q + 2
  1025. // q = q^ - c [C]
  1026. //
  1027. // We can compute the final remainder (that must be non-negative) as follows:
  1028. //
  1029. // r = { u2 u1 u0 } - v*q
  1030. // r = { u2 u1 u0 } - v*(q^ - c)
  1031. // r = { u2 u1 u0 } - v*q^ + v*c
  1032. // r = { u2 u1 u0 } - { v1 v0 } * q^ + v*c
  1033. // r = b^2*u2 + b*u1 + u0 - b*v1*q^ - v0*q^ + v*c
  1034. // r = b*(b*u2 + u1 - v1*q^) + u0 - v0*q^ + v*c
  1035. // r = b*({ u2 u1 } - v1*q^) + u0 - v0*q^ + v*c
  1036. // r = b*r^ + u0 - v0*q^ + v*c
  1037. // r = { r^ u0 } - v0*q^ + v*c [D]
  1038. //
  1039. // As we know `0 <= c <= 2` we can first check if `r < 0` requiring `c >= 1`:
  1040. //
  1041. // { r^ u0 } - v0*q^ < 0
  1042. // { r^ u0 } < v0*q^ [E]
  1043. //
  1044. // If we know that `r < 0` we can check if `r < -v` requiring `c = 2`:
  1045. //
  1046. // { r^ u0 } - v0*q^ < -v
  1047. // v0*q^ - { r^ u0 } > v [F]
  1048. //
  1049. // First we need to make sure `v1 >= b/2`, we can do this by multiplying the whole
  1050. // expression by `2^shift` so that the high bit of `v` is set.
  1051. uint32_t shift = ufbxi_lzcnt64(b);
  1052. a_hi = (a_hi << shift) | (shift ? a_lo >> (64 - shift) : 0);
  1053. a_lo <<= shift;
  1054. b <<= shift;
  1055. uint64_t v = b;
  1056. uint32_t v1 = (uint32_t)(v >> 32);
  1057. uint32_t v0 = (uint32_t)(v);
  1058. uint64_t q1, q0, r;
  1059. // q1, r = { a3 a2 a1 } / { b1 b0 }
  1060. {
  1061. uint64_t u2_u1 = a_hi;
  1062. uint32_t u0 = (uint32_t)(a_lo >> 32u);
  1063. uint64_t qh = u2_u1 / v1; // q^ = { u2 u1 } / v1 [A]
  1064. uint64_t rh = u2_u1 % v1; // r^ = { u2 u1 } % v1 [B]
  1065. uint64_t rh_u0 = rh << 32u | u0; // { r^ u0 }
  1066. uint64_t v0qh = v0 * qh; // v0*q^
  1067. uint32_t c = rh_u0 < v0qh ? 1 : 0; // { r^ u0 } < v0*q^ [E]
  1068. c += c & (v0qh - rh_u0 > v ? 1 : 0); // v0*q^ - { r^ u0 } > v [F]
  1069. q1 = qh - c; // q1 = q^ - c [C]
  1070. r = rh_u0 - v0qh + v*c; // r = { r^ u0 } - v0*q^ + v*c [D]
  1071. }
  1072. // q0, r = { r1 r0 a0 } / { b1 b0 }
  1073. {
  1074. uint64_t u2_u1 = r;
  1075. uint32_t u0 = (uint32_t)a_lo;
  1076. uint64_t qh = u2_u1 / v1; // q^ = { u2 u1 } / v1 [A]
  1077. uint64_t rh = u2_u1 % v1; // r^ = { u2 u1 } % v1 [B]
  1078. uint64_t rh_u0 = rh << 32u | u0; // { r^ u0 }
  1079. uint64_t v0qh = v0 * qh; // v0*q^
  1080. uint32_t c = rh_u0 < v0qh ? 1 : 0; // { r^ u0 } < v0*q^ [E]
  1081. c += c & (v0qh - rh_u0 > v ? 1 : 0); // v0*q^ - { r^ u0 } > v [F]
  1082. q0 = qh - c; // q0 = q^ - c [C]
  1083. r = rh_u0 - v0qh + v*c; // r = { r^ u0 } - v0*q^ + v*c [D]
  1084. }
  1085. // Un-normalize the remainder and return the quotinent
  1086. *p_rem = r >> shift;
  1087. return q1 << 32u | q0;
  1088. }
  1089. #endif
  1090. typedef enum {
  1091. UFBXI_PARSE_DOUBLE_ALLOW_FAST_PATH = 0x1,
  1092. UFBXI_PARSE_DOUBLE_VERIFY_LENGTH = 0x2,
  1093. } ufbxi_parse_double_flag;
  1094. static const uint64_t ufbxi_pow5_tab[] = {
  1095. UINT64_C(0x8000000000000000), // 5^0 * 2^63
  1096. UINT64_C(0xa000000000000000), // 5^1 * 2^61
  1097. UINT64_C(0xc800000000000000), // 5^2 * 2^59
  1098. UINT64_C(0xfa00000000000000), // 5^3 * 2^57
  1099. UINT64_C(0x9c40000000000000), // 5^4 * 2^54
  1100. UINT64_C(0xc350000000000000), // 5^5 * 2^52
  1101. UINT64_C(0xf424000000000000), // 5^6 * 2^50
  1102. UINT64_C(0x9896800000000000), // 5^7 * 2^47
  1103. UINT64_C(0xbebc200000000000), // 5^8 * 2^45
  1104. UINT64_C(0xee6b280000000000), // 5^9 * 2^43
  1105. UINT64_C(0x9502f90000000000), // 5^10 * 2^40
  1106. UINT64_C(0xba43b74000000000), // 5^11 * 2^38
  1107. UINT64_C(0xe8d4a51000000000), // 5^12 * 2^36
  1108. UINT64_C(0x9184e72a00000000), // 5^13 * 2^33
  1109. UINT64_C(0xb5e620f480000000), // 5^14 * 2^31
  1110. UINT64_C(0xe35fa931a0000000), // 5^15 * 2^29
  1111. UINT64_C(0x8e1bc9bf04000000), // 5^16 * 2^26
  1112. UINT64_C(0xb1a2bc2ec5000000), // 5^17 * 2^24
  1113. UINT64_C(0xde0b6b3a76400000), // 5^18 * 2^22
  1114. UINT64_C(0x8ac7230489e80000), // 5^19 * 2^19
  1115. UINT64_C(0xad78ebc5ac620000), // 5^20 * 2^17
  1116. UINT64_C(0xd8d726b7177a8000), // 5^21 * 2^15
  1117. UINT64_C(0x878678326eac9000), // 5^22 * 2^12
  1118. UINT64_C(0xa968163f0a57b400), // 5^23 * 2^10
  1119. UINT64_C(0xd3c21bcecceda100), // 5^24 * 2^8
  1120. UINT64_C(0x84595161401484a0), // 5^25 * 2^5
  1121. UINT64_C(0xa56fa5b99019a5c8), // 5^26 * 2^3
  1122. UINT64_C(0xcecb8f27f4200f3a), // 5^27 * 2^1
  1123. };
  1124. static const int8_t ufbxi_pow2_tab[] = {
  1125. 62, 59, 56, 53, 49, 46, 43, 39, 36, 33, 29, 26, 23, 19, 16, 13, 9, 6, 3, -1, -4, -7, -11, -14, -17, -21, -24, -27,
  1126. };
  1127. static const double ufbxi_pow10_tab_f64[] = {
  1128. 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22,
  1129. };
  1130. static ufbxi_noinline uint32_t ufbxi_parse_double_init_flags()
  1131. {
  1132. // We require evaluation in double precision, either for doubles (0) or always (1)
  1133. // and rounding to nearest, which we can check for with `1 + eps == 1 - eps`.
  1134. #if defined(FLT_EVAL_METHOD)
  1135. #if FLT_EVAL_METHOD == 0 || FLT_EVAL_METHOD == 1
  1136. static volatile double ufbxi_volatile_eps = 2.2250738585072014e-308;
  1137. if (1.0 + ufbxi_volatile_eps == 1.0 - ufbxi_volatile_eps) return UFBXI_PARSE_DOUBLE_ALLOW_FAST_PATH;
  1138. #endif
  1139. #endif
  1140. return 0;
  1141. }
  1142. static ufbxi_noinline double ufbxi_parse_double_slow(const char *str, char **end)
  1143. {
  1144. // TODO: Locales
  1145. return strtod(str, end);
  1146. }
  1147. static ufbxi_noinline double ufbxi_parse_double(const char *str, size_t max_length, char **end, uint32_t flags)
  1148. {
  1149. // TODO: Use this for optimizing digit parsing
  1150. (void)max_length;
  1151. uint64_t integer = 0;
  1152. uint32_t n_integer = 0;
  1153. int32_t n_decimals = 0;
  1154. uint32_t n_exp = 0;
  1155. bool negative = false;
  1156. // Parse /[+-]?[0-9]*(\.[0-9]*)([eE][+-]?[0-9]*)?/ retaining all digits
  1157. // in `integer` and number of decimals in `n_decimals`, exponent simply
  1158. // modifies `n_decimals` accordingly.
  1159. const char *p = str;
  1160. if (*p == '-') {
  1161. negative = true;
  1162. p++;
  1163. } else if (*p == '+') {
  1164. p++;
  1165. }
  1166. while (((uint32_t)*p - '0') < 10) {
  1167. integer = integer * 10 + (uint64_t)(*p++ - '0');
  1168. n_integer++;
  1169. }
  1170. if (*p == '.') {
  1171. p++;
  1172. while (((uint32_t)*p - '0') < 10) {
  1173. integer = integer * 10 + (uint64_t)(*p++ - '0');
  1174. n_integer++;
  1175. n_decimals++;
  1176. }
  1177. }
  1178. if ((*p | 0x20) == 'e') {
  1179. p++;
  1180. int32_t exp = 0;
  1181. int32_t exp_sign = -1;
  1182. if (*p == '-') {
  1183. p++;
  1184. exp_sign = 1;
  1185. } else if (*p == '+') {
  1186. p++;
  1187. }
  1188. while (((uint32_t)*p - '0') < 10) {
  1189. exp = exp * 10 + (int32_t)(*p++ - '0');
  1190. n_exp++;
  1191. }
  1192. n_decimals += exp * exp_sign;
  1193. }
  1194. *end = (char*)p;
  1195. // Check that the number is not potentially truncated.
  1196. if (ufbxi_to_size(p - str) >= max_length && (flags & UFBXI_PARSE_DOUBLE_VERIFY_LENGTH) != 0) {
  1197. *end = NULL;
  1198. return 0.0;
  1199. }
  1200. // Overflowed either 64-bit `integer` or 31-bit `exp`.
  1201. if (n_integer > 19 || n_exp > 9 || (integer >> 63) != 0) {
  1202. return ufbxi_parse_double_slow(str, end);
  1203. }
  1204. // Both power of 10 and integer are exactly representable as doubles
  1205. // Powers of 10 are factored as 2*5, and 2^N can be always exactly represented.
  1206. if ((flags & UFBXI_PARSE_DOUBLE_ALLOW_FAST_PATH) != 0 && n_decimals >= -22 && n_decimals <= 22 && (integer >> 53) == 0) {
  1207. double value;
  1208. if (n_decimals > 0) {
  1209. value = (double)integer / ufbxi_pow10_tab_f64[n_decimals];
  1210. } else {
  1211. value = (double)integer * ufbxi_pow10_tab_f64[-n_decimals];
  1212. }
  1213. return negative ? -value : value;
  1214. }
  1215. // Cannot handle positive exponents here, fortunately the fast case should
  1216. // take care of most of them, for negative exponents we can only handle
  1217. // up to e-27 as `5^28 > 2^64` and cannot be used as a divisor below.
  1218. if (n_decimals < 0) {
  1219. return ufbxi_parse_double_slow(str, end);
  1220. } else if (!n_decimals || !integer) {
  1221. double value = (double)integer;
  1222. return negative ? -value : value;
  1223. } else if (n_decimals > 27) {
  1224. return ufbxi_parse_double_slow(str, end);
  1225. }
  1226. // We want to compute `integer / 10^N` precisely, we can do this
  1227. // using 128-bit division `2^64 * dividend / divisor`:
  1228. // dividend = integer * 2^S (S set such that highest bit is 62)
  1229. // divisor = 10^N * 2^T (T set such that highest bit is 63)
  1230. // We have to compensate for the shifts in the exponent:
  1231. // (2^64 * integer * 2^S) / (10^N * 2^T) * 2^(-1 - S + T)
  1232. // To get larger exponent range split 10^N to 5^N * 2^N and move 2^N to the exponent
  1233. // (2^64 * integer * 2^S) / (5^N * 2^T) * 2^(-1 - S + T - N)
  1234. uint32_t shift = ufbxi_lzcnt64(integer) - 1;
  1235. uint64_t dividend = integer << shift;
  1236. uint64_t divisor = ufbxi_pow5_tab[n_decimals];
  1237. int32_t exponent = (int32_t)ufbxi_pow2_tab[n_decimals] - (int32_t)shift; // (-1 + T - N) - S
  1238. uint64_t rem_hi;
  1239. uint64_t b_hi = ufbxi_div128(dividend, 0, divisor, &rem_hi);
  1240. // Align the mantissa so that high bit is set, due to the shifting of the
  1241. // divisor and dividend the smallest result is `2^62 + N`, so we need to
  1242. // shift at most by one bit.
  1243. uint64_t b_bit = 1 - (b_hi >> 63u);
  1244. uint64_t mantissa = b_hi << b_bit;
  1245. exponent -= (int32_t)b_bit;
  1246. // Round to 53 bits, accounting for potential remainder.
  1247. bool nonzero_tail = rem_hi != 0;
  1248. bool r_odd = mantissa & (1 << 11u);
  1249. bool r_round = mantissa & (1 << 10u);
  1250. bool r_tail = (mantissa & ((1 << 10u) - 1)) != 0 || nonzero_tail;
  1251. uint64_t round = (r_round && (r_odd || r_tail)) ? 1u : 0u;
  1252. // Assemble the IEEE 754 binary64 number.
  1253. uint64_t bits
  1254. = (uint64_t)negative << 63u
  1255. | (uint64_t)(exponent + 1023) << 52u
  1256. | ((mantissa >> 11u) & ~(UINT64_C(1) << 52u));
  1257. bits += round;
  1258. // Type punning via unions is safe in C but in C++ the only safe way
  1259. // (pre std::bit_cast) is to use `memcpy()` and hope it gets optimized out.
  1260. #if defined(__cplusplus)
  1261. double result;
  1262. memcpy(&result, &bits, 8);
  1263. return result;
  1264. #else
  1265. union { uint64_t u; double d; } u_to_d;
  1266. u_to_d.u = bits;
  1267. return u_to_d.d;
  1268. #endif
  1269. }
  1270. static ufbxi_forceinline int64_t ufbxi_parse_int64(const char *str, char **end)
  1271. {
  1272. uint64_t abs_val = 0;
  1273. bool negative = *str == '-';
  1274. bool positive = *str == '+';
  1275. size_t init_len = (negative | positive) ? 1 : 0;
  1276. size_t len = init_len;
  1277. for (; len < 30; len++) {
  1278. char c = str[len];
  1279. if (!(c >= '0' && c <= '9')) break;
  1280. abs_val = 10 * abs_val + (uint64_t)(c - '0');
  1281. }
  1282. if (len == 30 || len == init_len) {
  1283. *end = NULL;
  1284. return 0;
  1285. }
  1286. // TODO: Wrap/clamp?
  1287. *end = (char*)str + len;
  1288. return negative ? -(int64_t)abs_val : (int64_t)abs_val;
  1289. }
  1290. // -- DEFLATE implementation
  1291. #if !defined(ufbx_inflate)
  1292. // Lookup data: [0:5] extra bits [5:8] flags [16:32] base value
  1293. // Generated by `misc/deflate_lut.py`
  1294. static const uint32_t ufbxi_deflate_length_lut[] = {
  1295. 0x00000020, 0x00030040, 0x00040040, 0x00050040, 0x00060040, 0x00070040, 0x00080040, 0x00090040,
  1296. 0x000a0040, 0x000b0041, 0x000d0041, 0x000f0041, 0x00110041, 0x00130042, 0x00170042, 0x001b0042,
  1297. 0x001f0042, 0x00230043, 0x002b0043, 0x00330043, 0x003b0043, 0x00430044, 0x00530044, 0x00630044,
  1298. 0x00730044, 0x00830045, 0x00a30045, 0x00c30045, 0x00e30045, 0x01020040, 0x00010020, 0x00010020,
  1299. };
  1300. static const uint32_t ufbxi_deflate_dist_lut[] = {
  1301. 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050001, 0x00070001, 0x00090002, 0x000d0002,
  1302. 0x00110003, 0x00190003, 0x00210004, 0x00310004, 0x00410005, 0x00610005, 0x00810006, 0x00c10006,
  1303. 0x01010007, 0x01810007, 0x02010008, 0x03010008, 0x04010009, 0x06010009, 0x0801000a, 0x0c01000a,
  1304. 0x1001000b, 0x1801000b, 0x2001000c, 0x3001000c, 0x4001000d, 0x6001000d, 0x00010020, 0x00010020,
  1305. };
  1306. static const uint8_t ufbxi_deflate_code_length_permutation[] = {
  1307. 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15,
  1308. };
  1309. #define UFBXI_INFLATE_FAST_MIN_IN 8
  1310. #define UFBXI_INFLATE_FAST_MIN_OUT 2
  1311. #define UFBXI_HUFF_MAX_BITS 16
  1312. #define UFBXI_HUFF_MAX_VALUE 288
  1313. #define UFBXI_HUFF_FAST_BITS 10
  1314. #define UFBXI_HUFF_FAST_SIZE (1 << UFBXI_HUFF_FAST_BITS)
  1315. #define UFBXI_HUFF_FAST_MASK (UFBXI_HUFF_FAST_SIZE - 1)
  1316. #define UFBXI_HUFF_MAX_LONG_BITS 5
  1317. #define UFBXI_HUFF_MAX_LONG_SYMS 380
  1318. #define UFBXI_HUFF_CODELEN_FAST_BITS 8
  1319. #define UFBXI_HUFF_CODELEN_FAST_MASK ((1<<UFBXI_HUFF_CODELEN_FAST_BITS)-1)
  1320. #define UFBXI_HUFF_MAX_EXTRA_SYMS 32
  1321. typedef struct {
  1322. // Number of bytes left to read from `read_fn()`
  1323. size_t input_left;
  1324. // User-supplied read callback
  1325. ufbx_read_fn *read_fn;
  1326. void *read_user;
  1327. // Buffer to read to from `read_fn()`, may point to `local_buffer` if user
  1328. // didn't supply a suitable buffer.
  1329. char *buffer;
  1330. size_t buffer_size;
  1331. // Current chunk of data to process, either the initial buffer of input
  1332. // or part of `buffer`.
  1333. const char *chunk_begin; // < Begin of the buffer
  1334. const char *chunk_ptr; // < Next bytes to read to `bits`
  1335. const char *chunk_yield; // < End of data before needing to call `ufbxi_bit_yield()`
  1336. const char *chunk_end; // < End of data before needing to call `ufbxi_bit_refill()`
  1337. const char *chunk_real_end; // < Actual end of the data buffer
  1338. // Amount of bytes read before the current chunk
  1339. size_t num_read_before_chunk;
  1340. uint64_t progress_bias;
  1341. uint64_t progress_total;
  1342. size_t progress_interval;
  1343. uint64_t bits; // < Buffered bits
  1344. size_t left; // < Number of valid low bits in `bits`
  1345. // Progress tracking, maybe `NULL` it not requested
  1346. ufbx_progress_cb progress_cb;
  1347. // When `progress_cb.fn()` returns `false` set the `cancelled` flag and
  1348. // set the buffered bits to `cancel_bits`.
  1349. uint64_t cancel_bits;
  1350. bool cancelled;
  1351. char local_buffer[256];
  1352. } ufbxi_bit_stream;
  1353. // Packed symbol information:
  1354. //
  1355. // [0:5] total_bits // [fast=1] Number of bits in the symbol _including_ extra bits
  1356. // [0:5] extra_mask // [fast=0] Mask of extra bits to use
  1357. // [5] end // 1 if end/invalid symbol, always 0 if `fast` (*1)
  1358. // [6] match // 1 if the symbol is a match length, always 0 in non `lit_length` trees (always 0 if `end`)
  1359. // [7] fast // 1 if the symbol can be determined from the table bits and `end=0`
  1360. // [8:16] lit_byte // [lit_length] Literal byte
  1361. // [8:16] len_index // [lit_length, match=1] Match length index
  1362. // [8:16] dist_index // [dist] Match distance index
  1363. // [8:16] code_length // [code_length] Dynamic Huffman code length code
  1364. // [8:16] long_offset // [fast_sym, fast=0, extra_mask>0] Base offset (halved) to `long_sym[]`
  1365. // [8:16] code_prefix // [fast_sym, fast=0, extra_mask=0] First 8-bits of the code (reverse of the lookup)
  1366. //
  1367. // (*1) Not allowing `end` if `fast` serves a dual purpose: It allows us to omit a check for the end symbol in the
  1368. // fast path and allows using the symbol as a 64-bit shift amount (x64/ARM64/WASM have native modulo 64 shifts).
  1369. //
  1370. // Valid bit patterns, all other patterns are forbidden (`sorted_to_sym[]` contains same patterns as `long_sym[]`):
  1371. //
  1372. // tree b e m f v
  1373. //
  1374. // lit_length.fast_sym[] N 0 0 1 L // Short N bit code (no extra allowed) for literal byte L
  1375. // lit_length.fast_sym[] N 0 1 1 I // Short N bit code (huff+extra bits) for length index I
  1376. // lit_length.fast_sym[] M 0 0 0 X // Long code at `lit_length.long_sym[X*2 + ((bits>>FAST_BITS) & M)]`
  1377. // lit_length.fast_sym[] 0 0 0 0 R // Extra long code with prefix R, use `lit_length.sorted_to_sym[]` to resolve (*1)
  1378. // lit_length.fast_sym[] N 1 0 0 0 // Short N bit code for end-of-block (256) symbol
  1379. // lit_length.fast_sym[] 0 1 0 0 1 // Invalid lit_length code
  1380. //
  1381. // lit_length.long_sym[] N 0 0 0 L // Long N bit code (no extra allowed) for literal byte L
  1382. // lit_length.long_sym[] N 0 1 0 I // Long N bit code (huff+extra bits) for length index I
  1383. // lit_length.long_sym[] N 1 0 0 0 // Long N bit code for end-of-block (256) symbol
  1384. // lit_length.long_sym[] 0 1 0 0 1 // Invalid lit_length code
  1385. //
  1386. // dist.fast_sym[] N 0 0 1 L // Short N bit code (huff+extra bits) for distance index I
  1387. // dist.fast_sym[] M 0 0 0 X // Long code at `dist.long_sym[X*2 + ((bits>>FAST_BITS) & M)]`
  1388. // dist.fast_sym[] 0 0 0 0 R // Extra long code with prefix R, use `dist.sorted_to_sym[]` to resolve (*1)
  1389. // dist.fast_sym[] N 1 0 0 1 // Unused symbol 30-31 or invalid distance code
  1390. //
  1391. // dist.long_sym[] N 0 0 0 I // Long N bit code (huff+extra bits) for distance index I
  1392. // dist.long_sym[] N 1 0 0 1 // Unused symbol 30-31 or invalid distance code
  1393. //
  1394. // code_length.fast_sym[] N 0 0 1 B // Short N bit code (huff only, extra handled explicitly) for symbol bit count B
  1395. // code_length.fast_sym[] M 0 0 0 X // Long code at `dist.long_sym[X*2 + ((bits>>FAST_BITS) & M)]`
  1396. // code_length.fast_sym[] 0 0 0 0 R // Extra long code with prefix R, use `code_length.sorted_to_sym[]` to resolve (*1)
  1397. //
  1398. // code_length.long_sym[] N 0 0 0 B // Long N bit code (huff only, extra handled explicitly) for symbol bit count B
  1399. //
  1400. // (*1) Never necessary if `fast_bits >= 10` due to `long_sym[]` covering all possible codes,
  1401. //
  1402. typedef uint16_t ufbxi_huff_sym;
  1403. #define ufbxi_huff_sym_total_bits(sym) ((uint32_t)(sym) & 0x1f)
  1404. #define ufbxi_huff_sym_long_mask(sym) ((uint32_t)(sym) & 0x1f)
  1405. #define ufbxi_huff_sym_long_offset(sym) ((uint32_t)(sym) >> 7u)
  1406. #define ufbxi_huff_sym_value(sym) ((uint32_t)(sym) >> 8u)
  1407. enum {
  1408. UFBXI_HUFF_SYM_END = 0x20,
  1409. UFBXI_HUFF_SYM_MATCH = 0x40,
  1410. UFBXI_HUFF_SYM_FAST = 0x80,
  1411. };
  1412. #define UFBXI_HUFF_ERROR_SYM ((ufbxi_huff_sym)0x0120) // Error symbol, END (value 1)
  1413. #define UFBXI_HUFF_UNINITIALIZED_SYM ((ufbxi_huff_sym)0x0220) // Uninitialized symbol for regression, END (value 2)
  1414. typedef struct {
  1415. ufbxi_huff_sym fast_sym[UFBXI_HUFF_FAST_SIZE]; // < Lookup from N bytes to symbol information
  1416. ufbxi_huff_sym long_sym[UFBXI_HUFF_MAX_LONG_SYMS]; // < Fast long symbol lookup
  1417. ufbxi_huff_sym sorted_to_sym[UFBXI_HUFF_MAX_VALUE]; // < Symbol information per sorted index
  1418. uint32_t extra_shift_base[UFBXI_HUFF_MAX_EXTRA_SYMS]; // < [0:6] shift [16:32] base value
  1419. uint16_t extra_mask[UFBXI_HUFF_MAX_EXTRA_SYMS]; // < Mask for extra bits
  1420. uint16_t past_max_code[UFBXI_HUFF_MAX_BITS]; // < One past maximum code value per bit length
  1421. int16_t code_to_sorted[UFBXI_HUFF_MAX_BITS]; // < Code to sorted symbol index per bit length
  1422. uint32_t num_symbols;
  1423. uint32_t end_of_block_bits;
  1424. } ufbxi_huff_tree;
  1425. typedef struct {
  1426. union {
  1427. struct {
  1428. ufbxi_huff_tree lit_length;
  1429. ufbxi_huff_tree dist;
  1430. };
  1431. ufbxi_huff_tree trees[2];
  1432. };
  1433. uint32_t fast_bits;
  1434. } ufbxi_trees;
  1435. typedef struct {
  1436. bool initialized;
  1437. ufbxi_trees static_trees;
  1438. } ufbxi_inflate_retain_imp;
  1439. ufbx_static_assert(inflate_retain_size, sizeof(ufbxi_inflate_retain_imp) <= sizeof(ufbx_inflate_retain));
  1440. typedef struct {
  1441. ufbxi_bit_stream stream;
  1442. uint32_t fast_bits;
  1443. char *out_begin;
  1444. char *out_ptr;
  1445. char *out_end;
  1446. } ufbxi_deflate_context;
  1447. static ufbxi_forceinline uint32_t
  1448. ufbxi_bit_reverse(uint32_t mask, uint32_t num_bits)
  1449. {
  1450. ufbxi_dev_assert(num_bits <= 16);
  1451. uint32_t x = mask;
  1452. x = (((x & 0xaaaa) >> 1) | ((x & 0x5555) << 1));
  1453. x = (((x & 0xcccc) >> 2) | ((x & 0x3333) << 2));
  1454. x = (((x & 0xf0f0) >> 4) | ((x & 0x0f0f) << 4));
  1455. x = (((x & 0xff00) >> 8) | ((x & 0x00ff) << 8));
  1456. return x >> (16 - num_bits);
  1457. }
  1458. static ufbxi_noinline const char *
  1459. ufbxi_bit_chunk_refill(ufbxi_bit_stream *s, const char *ptr)
  1460. {
  1461. // Copy any left-over data to the beginning of `buffer`
  1462. size_t left = ufbxi_to_size(s->chunk_real_end - ptr);
  1463. ufbxi_dev_assert(left < 64);
  1464. if (left > 0) memmove(s->buffer, ptr, left);
  1465. s->num_read_before_chunk += ufbxi_to_size(ptr - s->chunk_begin);
  1466. // Read more user data if the user supplied a `read_fn()`, otherwise
  1467. // we assume the initial data chunk is the whole input buffer.
  1468. if (s->read_fn && !s->cancelled) {
  1469. size_t to_read = ufbxi_min_sz(s->input_left, s->buffer_size - left);
  1470. if (to_read > 0) {
  1471. size_t num_read = s->read_fn(s->read_user, s->buffer + left, to_read);
  1472. // TODO: IO error, should unify with (currently broken) cancel logic
  1473. if (num_read > to_read) num_read = 0;
  1474. ufbxi_dev_assert(s->input_left >= num_read);
  1475. s->input_left -= num_read;
  1476. left += num_read;
  1477. }
  1478. }
  1479. // Pad the rest with zeros
  1480. if (left < 64) {
  1481. memset(s->buffer + left, 0, 64 - left);
  1482. left = 64;
  1483. }
  1484. s->chunk_begin = s->buffer;
  1485. s->chunk_ptr = s->buffer;
  1486. s->chunk_end = s->buffer + left - 8;
  1487. s->chunk_real_end = s->buffer + left;
  1488. return s->buffer;
  1489. }
  1490. static ufbxi_noinline void ufbxi_bit_stream_init(ufbxi_bit_stream *s, const ufbx_inflate_input *input)
  1491. {
  1492. size_t data_size = input->data_size;
  1493. if (data_size > input->total_size) {
  1494. data_size = input->total_size;
  1495. }
  1496. s->read_fn = input->read_fn;
  1497. s->read_user = input->read_user;
  1498. s->progress_cb = input->progress_cb;
  1499. s->chunk_begin = (const char*)input->data;
  1500. s->chunk_ptr = (const char*)input->data;
  1501. s->chunk_end = ufbxi_add_ptr((const char*)input->data, ufbxi_max_sz(8, data_size) - 8);
  1502. s->chunk_real_end = ufbxi_add_ptr((const char*)input->data, data_size);
  1503. s->input_left = input->total_size - data_size;
  1504. // Use the user buffer if it's large enough, otherwise `local_buffer`
  1505. if (input->buffer_size > sizeof(s->local_buffer)) {
  1506. s->buffer = (char*)input->buffer;
  1507. s->buffer_size = input->buffer_size;
  1508. } else {
  1509. s->buffer = s->local_buffer;
  1510. s->buffer_size = sizeof(s->local_buffer);
  1511. }
  1512. s->num_read_before_chunk = 0;
  1513. s->progress_bias = input->progress_size_before;
  1514. s->progress_total = input->total_size + input->progress_size_before + input->progress_size_after;
  1515. if (!s->progress_cb.fn || input->progress_interval_hint >= SIZE_MAX) {
  1516. s->progress_interval = SIZE_MAX;
  1517. } else if (input->progress_interval_hint > 0) {
  1518. s->progress_interval = (size_t)input->progress_interval_hint;
  1519. } else {
  1520. s->progress_interval = 0x4000;
  1521. }
  1522. s->cancelled = false;
  1523. // Clear the initial bit buffer
  1524. s->bits = 0;
  1525. s->left = 0;
  1526. // If the initial data buffer is not large enough to be read directly
  1527. // from refill the chunk once.
  1528. if (data_size < 64) {
  1529. ufbxi_bit_chunk_refill(s, s->chunk_begin);
  1530. }
  1531. if (s->progress_cb.fn && ufbxi_to_size(s->chunk_end - s->chunk_ptr) > s->progress_interval + 8) {
  1532. s->chunk_yield = s->chunk_ptr + s->progress_interval;
  1533. } else {
  1534. s->chunk_yield = s->chunk_end;
  1535. }
  1536. }
  1537. static ufbxi_noinline const char *
  1538. ufbxi_bit_yield(ufbxi_bit_stream *s, const char *ptr)
  1539. {
  1540. if (ptr > s->chunk_end) {
  1541. ptr = ufbxi_bit_chunk_refill(s, ptr);
  1542. }
  1543. if (s->progress_cb.fn) {
  1544. size_t num_read = s->num_read_before_chunk + ufbxi_to_size(ptr - s->chunk_begin);
  1545. ufbx_progress progress = { s->progress_bias + num_read, s->progress_total };
  1546. uint32_t result = (uint32_t)s->progress_cb.fn(s->progress_cb.user, &progress);
  1547. ufbx_assert(result == UFBX_PROGRESS_CONTINUE || result == UFBX_PROGRESS_CANCEL);
  1548. if (result == UFBX_PROGRESS_CANCEL) {
  1549. s->cancelled = true;
  1550. ptr = s->local_buffer;
  1551. s->buffer = s->local_buffer;
  1552. s->buffer_size = sizeof(s->local_buffer);
  1553. s->chunk_begin = ptr;
  1554. s->chunk_ptr = ptr;
  1555. s->chunk_end = ptr + sizeof(s->local_buffer) - 8;
  1556. s->chunk_real_end = ptr + sizeof(s->local_buffer);
  1557. memset(s->local_buffer, 0, sizeof(s->local_buffer));
  1558. }
  1559. }
  1560. if (s->progress_cb.fn && ufbxi_to_size(s->chunk_end - ptr) > s->progress_interval + 8) {
  1561. s->chunk_yield = ptr + s->progress_interval;
  1562. } else {
  1563. s->chunk_yield = s->chunk_end;
  1564. }
  1565. return ptr;
  1566. }
  1567. static ufbxi_forceinline void
  1568. ufbxi_bit_refill(uint64_t *p_bits, size_t *p_left, const char **p_data, ufbxi_bit_stream *s)
  1569. {
  1570. if (*p_data > s->chunk_yield) {
  1571. *p_data = ufbxi_bit_yield(s, *p_data);
  1572. if (s->cancelled) {
  1573. // Force an end-of-block symbol when cancelled so we don't need an
  1574. // extra branch in the chunk decoding loop.
  1575. *p_bits = s->cancel_bits;
  1576. }
  1577. }
  1578. // See https://fgiesen.wordpress.com/2018/02/20/reading-bits-in-far-too-many-ways-part-2/
  1579. // variant 4. This branchless refill guarantees [56,63] bits to be valid in `*p_bits`.
  1580. ufbxi_regression_assert(*p_left <= 64); \
  1581. *p_bits |= ufbxi_read_u64(*p_data) << *p_left;
  1582. *p_data += (63 - *p_left) >> 3;
  1583. *p_left |= 56;
  1584. }
  1585. // See `ufbxi_bit_refill()`
  1586. #define ufbxi_macro_bit_refill_fast(m_bits, m_left, m_data, m_refill_bits) do { \
  1587. ufbxi_regression_assert(m_left <= 64); \
  1588. m_bits |= m_refill_bits << m_left; \
  1589. m_data += (63 - m_left) >> 3; \
  1590. m_left |= 56; \
  1591. } while (0)
  1592. static ufbxi_noinline int
  1593. ufbxi_bit_copy_bytes(void *dst, ufbxi_bit_stream *s, size_t len)
  1594. {
  1595. ufbx_assert(s->left % 8 == 0);
  1596. char *ptr = (char*)dst;
  1597. // Copy the buffered bits first
  1598. while (len > 0 && s->left > 0) {
  1599. *ptr++ = (char)(uint8_t)s->bits;
  1600. len -= 1;
  1601. s->bits >>= 8;
  1602. s->left -= 8;
  1603. }
  1604. // We need to clear the top bits as there may be data
  1605. // read ahead past `s->left` in some cases
  1606. s->bits = 0;
  1607. // Copy the current chunk
  1608. size_t chunk_left = ufbxi_to_size(s->chunk_real_end - s->chunk_ptr);
  1609. if (chunk_left >= len) {
  1610. memcpy(ptr, s->chunk_ptr, len);
  1611. s->chunk_ptr += len;
  1612. return 1;
  1613. } else {
  1614. memcpy(ptr, s->chunk_ptr, chunk_left);
  1615. s->chunk_ptr += chunk_left;
  1616. ptr += chunk_left;
  1617. len -= chunk_left;
  1618. }
  1619. // Read extra bytes from user
  1620. if (len > s->input_left) return 0;
  1621. size_t num_read = 0;
  1622. if (s->read_fn) {
  1623. num_read = s->read_fn(s->read_user, ptr, len);
  1624. s->input_left -= num_read;
  1625. }
  1626. return num_read == len;
  1627. }
  1628. // 0: Success
  1629. // -1: Overfull
  1630. // -2: Underfull
  1631. static ufbxi_noinline ptrdiff_t
  1632. ufbxi_huff_build_imp(ufbxi_huff_tree *tree, uint8_t *sym_bits, uint32_t sym_count, const uint32_t *sym_extra, uint32_t sym_extra_offset, uint32_t fast_bits, uint32_t *bits_counts)
  1633. {
  1634. uint32_t fast_mask = (1u << fast_bits) - 1;
  1635. ufbx_assert(sym_count <= UFBXI_HUFF_MAX_VALUE);
  1636. tree->num_symbols = sym_count;
  1637. uint32_t nonzero_sym_count = sym_count - bits_counts[0];
  1638. uint32_t total_syms[UFBXI_HUFF_MAX_BITS]; // ufbxi_uninit
  1639. uint32_t first_code[UFBXI_HUFF_MAX_BITS]; // ufbxi_uninit
  1640. tree->code_to_sorted[0] = INT16_MAX;
  1641. tree->past_max_code[0] = 0;
  1642. total_syms[0] = 0;
  1643. // Clear to uninitialized symbols
  1644. #if defined(UFBX_REGRESSION)
  1645. {
  1646. for (size_t i = 0; i < UFBXI_HUFF_FAST_SIZE; i++) {
  1647. tree->fast_sym[i] = UFBXI_HUFF_UNINITIALIZED_SYM;
  1648. }
  1649. for (size_t i = 0; i < UFBXI_HUFF_MAX_VALUE; i++) {
  1650. tree->sorted_to_sym[i] = UFBXI_HUFF_UNINITIALIZED_SYM;
  1651. }
  1652. for (size_t i = 0; i < UFBXI_HUFF_MAX_LONG_SYMS; i++) {
  1653. tree->long_sym[i] = UFBXI_HUFF_UNINITIALIZED_SYM;
  1654. }
  1655. }
  1656. #endif
  1657. uint32_t last_valid_prefix = 0;
  1658. // Resolve the maximum code per bit length and ensure that the tree is not
  1659. // overfull or underfull.
  1660. {
  1661. int num_codes_left = 1;
  1662. uint32_t code = 0;
  1663. uint32_t prev_count = 0;
  1664. uint32_t long_offset = 0;
  1665. for (uint32_t bits = 1; bits < UFBXI_HUFF_MAX_BITS; bits++) {
  1666. uint32_t count = bits_counts[bits];
  1667. code = (code + prev_count) << 1;
  1668. first_code[bits] = code;
  1669. tree->past_max_code[bits] = (uint16_t)(code + count);
  1670. uint32_t prev_syms = total_syms[bits - 1];
  1671. total_syms[bits] = prev_syms + count;
  1672. // Each bit level doubles the amount of codes and potentially removes some
  1673. num_codes_left = (num_codes_left << 1) - (int32_t)count;
  1674. if (num_codes_left < 0) {
  1675. return -1;
  1676. }
  1677. if (count > 0 && bits > fast_bits && bits - fast_bits <= UFBXI_HUFF_MAX_LONG_BITS) {
  1678. uint32_t shift = bits - fast_bits;
  1679. uint32_t last_inclusive = num_codes_left == 0 ? (1u<<shift) - 1u : 0u;
  1680. uint32_t first_prefix = code >> shift;
  1681. uint32_t last_prefix = (code + count + last_inclusive) >> shift;
  1682. uint32_t mask = (1u << shift) - 1u;
  1683. uint32_t half_step = 1u << (shift - 1u);
  1684. for (uint32_t prefix = first_prefix; prefix < last_prefix; prefix++) {
  1685. uint32_t rev_prefix = ufbxi_bit_reverse(prefix, fast_bits);
  1686. tree->fast_sym[rev_prefix] = (ufbxi_huff_sym)(mask | (long_offset << 8));
  1687. long_offset += half_step;
  1688. }
  1689. last_valid_prefix = last_prefix;
  1690. }
  1691. if (count > 0) {
  1692. tree->code_to_sorted[bits] = (int16_t)((int)prev_syms - (int)code);
  1693. } else {
  1694. tree->code_to_sorted[bits] = INT16_MAX;
  1695. }
  1696. prev_count = count;
  1697. }
  1698. // All codes should be used if there's more than one symbol, if there's only one symbol there should be
  1699. // only a single 1-bit code.
  1700. if (nonzero_sym_count > 1 && num_codes_left != 0) {
  1701. return -2;
  1702. } else if (nonzero_sym_count == 1 && total_syms[1] != 1) {
  1703. return -2;
  1704. }
  1705. // We should always have enough space for long symbols as we support up to 5 (UFBXI_HUFF_MAX_LONG_BITS)
  1706. // bits and the largest tree has 286 symbols. For each bit we may waste at most 2^bits slots (conservative)
  1707. // and in the end we may waste 2^5 slots giving us `286+2+4+8+16+32+32 = 380` (UFBXI_HUFF_MAX_LONG_SYMS)
  1708. ufbx_assert(long_offset <= UFBXI_HUFF_MAX_LONG_SYMS);
  1709. }
  1710. tree->end_of_block_bits = 0;
  1711. uint32_t num_extra = 0;
  1712. tree->extra_shift_base[0] = 0;
  1713. tree->extra_mask[0] = 0;
  1714. // Fill `fast_sym[]` with error symbols if necessary, we don't need to do this if we have two or more symbols
  1715. // as the tree is guaranteed to be full, which means we will populate the whole `fast_sym[]`
  1716. if (nonzero_sym_count <= 1) {
  1717. for (uint32_t i = 0; i <= fast_mask; i++) {
  1718. tree->fast_sym[i] = UFBXI_HUFF_ERROR_SYM;
  1719. }
  1720. }
  1721. // Generate per-length sorted-to-symbol and fast lookup tables
  1722. uint32_t bits_index[UFBXI_HUFF_MAX_BITS] = { 0 };
  1723. for (uint32_t i = 0; i < sym_count; i++) {
  1724. uint32_t bits = sym_bits[i];
  1725. if (bits == 0) continue;
  1726. uint32_t sym = i << 8 | bits;
  1727. if (i >= sym_extra_offset) {
  1728. uint32_t extra = sym_extra[i - sym_extra_offset];
  1729. sym += extra;
  1730. // Store length/distance codes with extra values in a table.
  1731. // TODO: This is unnecessary for small values
  1732. if ((extra & 0xffff001f) != 0 && (extra & 0x20) == 0) {
  1733. uint32_t ix = ++num_extra;
  1734. tree->extra_shift_base[ix] = (extra & 0xffff0000) | bits;
  1735. tree->extra_mask[ix] = (uint16_t)((1u << (extra & 0x1f)) - 1);
  1736. sym = (sym & 0xff) | ix << 8;
  1737. }
  1738. }
  1739. uint32_t index = bits_index[bits]++;
  1740. uint32_t sorted = total_syms[bits - 1] + index;
  1741. tree->sorted_to_sym[sorted] = (ufbxi_huff_sym)sym;
  1742. // Reverse the code and fill all fast lookups with the reversed prefix
  1743. uint32_t code = first_code[bits] + index;
  1744. uint32_t rev_code = ufbxi_bit_reverse(code, bits);
  1745. if (bits <= fast_bits) {
  1746. uint32_t fast_sym = sym;
  1747. // The `end` and `fast` flags are mutually exclusive
  1748. if ((fast_sym & UFBXI_HUFF_SYM_END) == 0) {
  1749. fast_sym |= UFBXI_HUFF_SYM_FAST;
  1750. }
  1751. uint32_t hi_max = 1u << (fast_bits - bits);
  1752. for (uint32_t hi = 0; hi < hi_max; hi++) {
  1753. ufbxi_regression_assert(nonzero_sym_count <= 1 || tree->fast_sym[rev_code | hi << bits] == UFBXI_HUFF_UNINITIALIZED_SYM);
  1754. tree->fast_sym[rev_code | hi << bits] = (ufbxi_huff_sym)fast_sym;
  1755. }
  1756. } else if (bits <= fast_bits + UFBXI_HUFF_MAX_LONG_BITS && (code >> (bits - fast_bits)) < last_valid_prefix) {
  1757. uint32_t fast_sym = tree->fast_sym[rev_code & fast_mask];
  1758. ufbxi_regression_assert(fast_sym != UFBXI_HUFF_UNINITIALIZED_SYM);
  1759. uint32_t long_bits = 0;
  1760. uint32_t long_mask = fast_sym;
  1761. while (long_bits < UFBXI_HUFF_MAX_LONG_BITS && (long_mask & 1) != 0) {
  1762. long_mask >>= 1;
  1763. long_bits += 1;
  1764. }
  1765. ufbxi_dev_assert(long_bits >= 1);
  1766. uint32_t long_base = fast_sym >> 7u; // aka (fast_sym >> 8) * 2
  1767. uint32_t lo_bits = bits - fast_bits;
  1768. uint32_t hi_max = 1u << (long_bits - lo_bits);
  1769. uint32_t rev_suffix = rev_code >> fast_bits;
  1770. for (uint32_t hi = 0; hi < hi_max; hi++) {
  1771. ufbxi_regression_assert(tree->long_sym[long_base + (rev_suffix | hi << lo_bits)] == UFBXI_HUFF_UNINITIALIZED_SYM);
  1772. tree->long_sym[long_base + (rev_suffix | hi << lo_bits)] = (ufbxi_huff_sym)sym;
  1773. }
  1774. } else {
  1775. uint32_t fast_sym = (code >> (bits - fast_bits)) << 8;
  1776. ufbxi_regression_assert(
  1777. tree->fast_sym[rev_code & fast_mask] == UFBXI_HUFF_UNINITIALIZED_SYM ||
  1778. tree->fast_sym[rev_code & fast_mask] == (ufbxi_huff_sym)fast_sym);
  1779. tree->fast_sym[rev_code & fast_mask] = (ufbxi_huff_sym)fast_sym;
  1780. }
  1781. // Make sure the end-of-block symbol goes through the slow path
  1782. // Also store the end-of-block code so we can interrupt decoding
  1783. if (i == 256) {
  1784. tree->end_of_block_bits = rev_code;
  1785. }
  1786. }
  1787. // Make sure all `fast_sym[]` are filled with an initialized value.
  1788. #if defined(UFBX_REGRESSION)
  1789. {
  1790. for (size_t i = 0; i < UFBXI_HUFF_FAST_SIZE; i++) {
  1791. if (i <= fast_mask) {
  1792. ufbx_assert(tree->fast_sym[i] != UFBXI_HUFF_UNINITIALIZED_SYM);
  1793. } else {
  1794. ufbx_assert(tree->fast_sym[i] == UFBXI_HUFF_UNINITIALIZED_SYM);
  1795. }
  1796. }
  1797. for (size_t i = 0; i < nonzero_sym_count; i++) {
  1798. ufbx_assert(tree->sorted_to_sym[i] != UFBXI_HUFF_UNINITIALIZED_SYM);
  1799. }
  1800. }
  1801. #endif
  1802. return 0;
  1803. }
  1804. // 0: Success
  1805. // -1: Overfull
  1806. // -2: Underfull
  1807. static ufbxi_noinline ptrdiff_t
  1808. ufbxi_huff_build(ufbxi_huff_tree *tree, uint8_t *sym_bits, uint32_t sym_count, const uint32_t *sym_extra, uint32_t sym_extra_offset, uint32_t fast_bits)
  1809. {
  1810. // Count the number of codes per bit length
  1811. // `bits_counts[0]` contains the number of non-used symbols
  1812. uint32_t bits_counts[UFBXI_HUFF_MAX_BITS]; // ufbxi_uninit
  1813. memset(bits_counts, 0, sizeof(bits_counts));
  1814. for (uint32_t i = 0; i < sym_count; i++) {
  1815. uint32_t bits = sym_bits[i];
  1816. ufbx_assert(bits < UFBXI_HUFF_MAX_BITS);
  1817. bits_counts[bits]++;
  1818. }
  1819. return ufbxi_huff_build_imp(tree, sym_bits, sym_count, sym_extra, sym_extra_offset, fast_bits, bits_counts);
  1820. }
  1821. static ufbxi_forceinline ufbxi_huff_sym
  1822. ufbxi_huff_decode_bits(const ufbxi_huff_tree *tree, uint64_t bits, uint32_t fast_bits, uint32_t fast_mask)
  1823. {
  1824. ufbxi_huff_sym sym = tree->fast_sym[bits & fast_mask];
  1825. ufbxi_regression_assert(sym != UFBXI_HUFF_UNINITIALIZED_SYM);
  1826. if ((sym & (UFBXI_HUFF_SYM_FAST|UFBXI_HUFF_SYM_END)) != 0) {
  1827. return sym;
  1828. }
  1829. uint32_t tail = (uint32_t)(bits >> fast_bits);
  1830. uint32_t long_mask = ufbxi_huff_sym_long_mask(sym);
  1831. if (long_mask) {
  1832. sym = tree->long_sym[ufbxi_huff_sym_long_offset(sym) + (tail & long_mask)];
  1833. ufbxi_regression_assert(sym != UFBXI_HUFF_UNINITIALIZED_SYM);
  1834. return sym;
  1835. }
  1836. ufbxi_dev_assert(fast_bits <= 8);
  1837. uint32_t code = ufbxi_huff_sym_value(sym);
  1838. uint32_t num_bits = fast_bits;
  1839. for (;;) {
  1840. code = code << 1 | (tail & 1);
  1841. tail >>= 1;
  1842. num_bits++;
  1843. ufbxi_regression_assert(num_bits < UFBXI_HUFF_MAX_BITS);
  1844. if (code < tree->past_max_code[num_bits]) {
  1845. sym = tree->sorted_to_sym[(int32_t)code + (int32_t)tree->code_to_sorted[num_bits]];
  1846. ufbxi_regression_assert(sym != UFBXI_HUFF_UNINITIALIZED_SYM);
  1847. return sym;
  1848. }
  1849. }
  1850. }
  1851. static ufbxi_noinline void ufbxi_init_static_huff(ufbxi_trees *trees, const ufbx_inflate_input *input)
  1852. {
  1853. ptrdiff_t err = 0;
  1854. // Override `fast_bits` if necessary, this must always be valid as it's checked in the beginning of `ufbx_inflate()`.
  1855. if (input && input->internal_fast_bits != 0) {
  1856. trees->fast_bits = (uint32_t)input->internal_fast_bits;
  1857. ufbx_assert(!(trees->fast_bits < 1 || trees->fast_bits == 9 || trees->fast_bits > 10));
  1858. } else {
  1859. trees->fast_bits = UFBXI_HUFF_FAST_BITS;
  1860. }
  1861. // 0-143: 8 bits, 144-255: 9 bits, 256-279: 7 bits, 280-287: 8 bits
  1862. uint8_t lit_length_bits[288]; // ufbxi_uninit
  1863. memset(lit_length_bits + 0, 8, 144 - 0);
  1864. memset(lit_length_bits + 144, 9, 256 - 144);
  1865. memset(lit_length_bits + 256, 7, 280 - 256);
  1866. memset(lit_length_bits + 280, 8, 288 - 280);
  1867. err |= ufbxi_huff_build(&trees->lit_length, lit_length_bits, sizeof(lit_length_bits), ufbxi_deflate_length_lut, 256, trees->fast_bits);
  1868. // "Distance codes 0-31 are represented by (fixed-length) 5-bit codes"
  1869. uint8_t dist_bits[32]; // ufbxi_uninit
  1870. memset(dist_bits + 0, 5, 32 - 0);
  1871. err |= ufbxi_huff_build(&trees->dist, dist_bits, sizeof(dist_bits), ufbxi_deflate_dist_lut, 0, trees->fast_bits);
  1872. // Building the static trees cannot fail as we use pre-defined code lengths.
  1873. ufbxi_ignore(err);
  1874. ufbx_assert(err == 0);
  1875. }
  1876. // 0: Success
  1877. // -1: Huffman Overfull
  1878. // -2: Huffman Underfull
  1879. // -3: Code 16 repeat overflow
  1880. // -4: Code 17 repeat overflow
  1881. // -5: Code 18 repeat overflow
  1882. // -6: Bad length code
  1883. // -7: Cancelled
  1884. static ufbxi_noinline ptrdiff_t ufbxi_init_dynamic_huff_tree(ufbxi_deflate_context *dc, const ufbxi_huff_tree *huff_code_length, ufbxi_huff_tree *tree,
  1885. uint32_t num_symbols, const uint32_t *sym_extra, uint32_t sym_extra_offset, uint32_t fast_bits)
  1886. {
  1887. uint8_t code_lengths[UFBXI_HUFF_MAX_VALUE]; // ufbxi_uninit
  1888. ufbx_assert(num_symbols <= UFBXI_HUFF_MAX_VALUE);
  1889. uint64_t bits = dc->stream.bits;
  1890. size_t left = dc->stream.left;
  1891. const char *data = dc->stream.chunk_ptr;
  1892. uint32_t bits_counts[UFBXI_HUFF_MAX_BITS]; // ufbxi_uninit
  1893. memset(bits_counts, 0, sizeof(bits_counts));
  1894. uint32_t symbol_index = 0;
  1895. uint8_t prev = 0;
  1896. while (symbol_index < num_symbols) {
  1897. ufbxi_bit_refill(&bits, &left, &data, &dc->stream);
  1898. if (dc->stream.cancelled) return -7;
  1899. ufbxi_huff_sym sym = ufbxi_huff_decode_bits(huff_code_length, bits, UFBXI_HUFF_CODELEN_FAST_BITS, UFBXI_HUFF_CODELEN_FAST_MASK);
  1900. ufbxi_regression_assert(sym != UFBXI_HUFF_UNINITIALIZED_SYM);
  1901. uint32_t inst = ufbxi_huff_sym_value(sym);
  1902. uint32_t sym_len = ufbxi_huff_sym_total_bits(sym);
  1903. bits >>= sym_len;
  1904. left -= sym_len;
  1905. if (inst <= 15) {
  1906. // "0 - 15: Represent code lengths of 0 - 15"
  1907. prev = (uint8_t)inst;
  1908. code_lengths[symbol_index++] = (uint8_t)inst;
  1909. bits_counts[(int32_t)inst]++;
  1910. } else if (inst == 16) {
  1911. // "16: Copy the previous code length 3 - 6 times. The next 2 bits indicate repeat length."
  1912. uint32_t num = 3 + ((uint32_t)bits & 0x3);
  1913. bits >>= 2;
  1914. left -= 2;
  1915. if (symbol_index + num > num_symbols) return -3;
  1916. memset(code_lengths + symbol_index, prev, num);
  1917. symbol_index += num;
  1918. bits_counts[(int32_t)prev] += num;
  1919. } else if (inst == 17) {
  1920. // "17: Repeat a code length of 0 for 3 - 10 times. (3 bits of length)"
  1921. uint32_t num = 3 + ((uint32_t)bits & 0x7);
  1922. bits >>= 3;
  1923. left -= 3;
  1924. if (symbol_index + num > num_symbols) return -4;
  1925. memset(code_lengths + symbol_index, 0, num);
  1926. symbol_index += num;
  1927. prev = 0;
  1928. bits_counts[0] += num;
  1929. } else if (inst == 18) {
  1930. // "18: Repeat a code length of 0 for 11 - 138 times (7 bits of length)"
  1931. uint32_t num = 11 + ((uint32_t)bits & 0x7f);
  1932. bits >>= 7;
  1933. left -= 7;
  1934. if (symbol_index + num > num_symbols) return -5;
  1935. memset(code_lengths + symbol_index, 0, num);
  1936. symbol_index += num;
  1937. prev = 0;
  1938. bits_counts[0] += num;
  1939. } else {
  1940. return -6;
  1941. }
  1942. }
  1943. ptrdiff_t err = ufbxi_huff_build_imp(tree, code_lengths, num_symbols, sym_extra, sym_extra_offset, fast_bits, bits_counts);
  1944. if (err != 0) return err;
  1945. dc->stream.bits = bits;
  1946. dc->stream.left = left;
  1947. dc->stream.chunk_ptr = data;
  1948. return 0;
  1949. }
  1950. static ufbxi_noinline ptrdiff_t
  1951. ufbxi_init_dynamic_huff(ufbxi_deflate_context *dc, ufbxi_trees *trees)
  1952. {
  1953. uint64_t bits = dc->stream.bits;
  1954. size_t left = dc->stream.left;
  1955. const char *data = dc->stream.chunk_ptr;
  1956. ufbxi_bit_refill(&bits, &left, &data, &dc->stream);
  1957. if (dc->stream.cancelled) return -28;
  1958. trees->fast_bits = dc->fast_bits;
  1959. // The header contains the number of Huffman codes in each of the three trees.
  1960. uint32_t num_lit_lengths = 257 + (uint32_t)(bits & 0x1f);
  1961. uint32_t num_dists = 1 + (uint32_t)(bits >> 5 & 0x1f);
  1962. uint32_t num_code_lengths = 4 + (uint32_t)(bits >> 10 & 0xf);
  1963. bits >>= 14;
  1964. left -= 14;
  1965. // Code lengths for the "code length" Huffman tree are represented literally
  1966. // 3 bits in order of: 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 up to
  1967. // `num_code_lengths`, rest of the code lengths are 0 (unused)
  1968. uint8_t code_lengths[19]; // ufbxi_uninit
  1969. memset(code_lengths, 0, sizeof(code_lengths));
  1970. for (size_t len_i = 0; len_i < num_code_lengths; len_i++) {
  1971. if (len_i == 14) {
  1972. ufbxi_bit_refill(&bits, &left, &data, &dc->stream);
  1973. if (dc->stream.cancelled) return -28;
  1974. }
  1975. code_lengths[ufbxi_deflate_code_length_permutation[len_i]] = (uint32_t)bits & 0x7;
  1976. bits >>= 3;
  1977. left -= 3;
  1978. }
  1979. dc->stream.bits = bits;
  1980. dc->stream.left = left;
  1981. dc->stream.chunk_ptr = data;
  1982. ufbxi_huff_tree huff_code_length; // ufbxi_uninit
  1983. ptrdiff_t err; // ufbxi_uninit
  1984. // Build the temporary "code length" Huffman tree used to encode the actual
  1985. // trees used to compress the data. Use that to build the literal/length and
  1986. // distance trees.
  1987. err = ufbxi_huff_build(&huff_code_length, code_lengths, ufbxi_arraycount(code_lengths), NULL, INT32_MAX, UFBXI_HUFF_CODELEN_FAST_BITS);
  1988. if (err) return -14 + 1 + err;
  1989. err = ufbxi_init_dynamic_huff_tree(dc, &huff_code_length, &trees->lit_length, num_lit_lengths, ufbxi_deflate_length_lut, 256, dc->fast_bits);
  1990. if (err) return err == -7 ? -28 : -16 + 1 + err;
  1991. err = ufbxi_init_dynamic_huff_tree(dc, &huff_code_length, &trees->dist, num_dists, ufbxi_deflate_dist_lut, 0, dc->fast_bits);
  1992. if (err) return err == -7 ? -28 : -22 + 1 + err;
  1993. return 0;
  1994. }
  1995. static ufbxi_noinline uint32_t ufbxi_adler32(const void *data, size_t size)
  1996. {
  1997. ufbxi_fast_uint a = 1, b = 0;
  1998. const char *p = (const char*)data;
  1999. // Adler-32 consists of two running sums modulo 65521. As an optimization
  2000. // we can accumulate N sums before applying the modulo, where N depends on
  2001. // the size of the type holding the sum.
  2002. const ufbxi_fast_uint num_before_wrap = sizeof(ufbxi_fast_uint) == 8 ? 380368439u : 5552u;
  2003. ufbxi_fast_uint size_left = size;
  2004. while (size_left > 0) {
  2005. ufbxi_fast_uint num = size_left <= num_before_wrap ? size_left : num_before_wrap;
  2006. size_left -= num;
  2007. const char *end = p + num;
  2008. // Align to 16 bytes
  2009. while (p != end && ((uintptr_t)p & 0xf) != 0) {
  2010. a += (ufbxi_fast_uint)(uint8_t)p[0]; b += a;
  2011. p++;
  2012. }
  2013. #if UFBXI_HAS_SSE
  2014. static const uint16_t factors[2][8] = {
  2015. { 16, 15, 14, 13, 12, 11, 10, 9, },
  2016. { 8, 7, 6, 5, 4, 3, 2, 1, },
  2017. };
  2018. const __m128i zero = _mm_setzero_si128();
  2019. const __m128i factor_1 = _mm_set1_epi16(1);
  2020. const __m128i factor_16 = _mm_set1_epi16(16);
  2021. const __m128i factor_lo = _mm_loadu_si128((const __m128i*)factors[0]);
  2022. const __m128i factor_hi = _mm_loadu_si128((const __m128i*)factors[1]);
  2023. for (;;) {
  2024. size_t chunk_size = ufbxi_min_sz(ufbxi_to_size(end - p), 5803) & ~(size_t)0xff;
  2025. if (chunk_size == 0) break;
  2026. const char *chunk_end = p + chunk_size;
  2027. __m128i s1 = zero;
  2028. __m128i s2 = zero;
  2029. while (p != chunk_end) {
  2030. __m128i s1_lo = zero, s1_hi = zero;
  2031. __m128i tmp_lo = zero, tmp_hi = zero;
  2032. ufbxi_nounroll for (size_t i = 0; i < 256; i += 32) {
  2033. __m128i d0 = _mm_load_si128((const __m128i*)(p + i + 0));
  2034. __m128i d1 = _mm_load_si128((const __m128i*)(p + i + 16));
  2035. tmp_lo = _mm_add_epi16(tmp_lo, s1_lo);
  2036. tmp_hi = _mm_add_epi16(tmp_hi, s1_hi);
  2037. s1_lo = _mm_add_epi16(s1_lo, _mm_unpacklo_epi8(d0, zero));
  2038. s1_hi = _mm_add_epi16(s1_hi, _mm_unpackhi_epi8(d0, zero));
  2039. tmp_lo = _mm_add_epi16(tmp_lo, s1_lo);
  2040. tmp_hi = _mm_add_epi16(tmp_hi, s1_hi);
  2041. s1_lo = _mm_add_epi16(s1_lo, _mm_unpacklo_epi8(d1, zero));
  2042. s1_hi = _mm_add_epi16(s1_hi, _mm_unpackhi_epi8(d1, zero));
  2043. }
  2044. s2 = _mm_add_epi32(s2, _mm_slli_epi32(s1, 8));
  2045. s1 = _mm_add_epi32(s1, _mm_madd_epi16(s1_lo, factor_1));
  2046. s1 = _mm_add_epi32(s1, _mm_madd_epi16(s1_hi, factor_1));
  2047. s2 = _mm_add_epi32(s2, _mm_madd_epi16(tmp_lo, factor_16));
  2048. s2 = _mm_add_epi32(s2, _mm_madd_epi16(tmp_hi, factor_16));
  2049. s2 = _mm_add_epi32(s2, _mm_madd_epi16(s1_lo, factor_lo));
  2050. s2 = _mm_add_epi32(s2, _mm_madd_epi16(s1_hi, factor_hi));
  2051. p += 256;
  2052. }
  2053. s1 = _mm_add_epi32(s1, _mm_shuffle_epi32(s1, _MM_SHUFFLE(2,3,0,1)));
  2054. s2 = _mm_add_epi32(s2, _mm_shuffle_epi32(s2, _MM_SHUFFLE(2,3,0,1)));
  2055. s1 = _mm_add_epi32(s1, _mm_shuffle_epi32(s1, _MM_SHUFFLE(1,0,3,2)));
  2056. s2 = _mm_add_epi32(s2, _mm_shuffle_epi32(s2, _MM_SHUFFLE(1,0,3,2)));
  2057. b += chunk_size * a;
  2058. a += (uint32_t)_mm_cvtsi128_si32(s1);
  2059. b += (uint32_t)_mm_cvtsi128_si32(s2);
  2060. }
  2061. #elif UFBX_LITTLE_ENDIAN
  2062. for (;;) {
  2063. size_t chunk_size = ufbxi_min_sz(ufbxi_to_size(end - p), 256*8/4) & ~(size_t)0xf;
  2064. if (chunk_size == 0) break;
  2065. const char *chunk_end = p + chunk_size;
  2066. uint64_t s1_lo = 0, s1_hi = 0;
  2067. uint64_t tmp, s2 = 0;
  2068. uint64_t mask8 = UINT64_C(0x00ff00ff00ff00ff);
  2069. uint64_t mask16 = UINT64_C(0x0000ffff0000ffff);
  2070. while (p != chunk_end) {
  2071. uint64_t d0 = *(const uint64_t*)p;
  2072. uint64_t d1 = *(const uint64_t*)(p + 8);
  2073. tmp = s1_lo + s1_hi;
  2074. s1_lo += d0 & mask8;
  2075. s1_hi += (d0 >> 8) & mask8;
  2076. tmp += s1_lo + s1_hi;
  2077. s1_lo += d1 & mask8;
  2078. s1_hi += (d1 >> 8) & mask8;
  2079. s2 += (tmp & mask16) + ((tmp >> 16) & mask16);
  2080. p += 16;
  2081. }
  2082. uint64_t s1 = s1_lo + s1_hi;
  2083. s1 = (s1 & mask16) + ((s1 >> 16u) & mask16);
  2084. ufbxi_fast_uint s1_sum = (ufbxi_fast_uint)(s1 + (s1 >> 32u));
  2085. ufbxi_fast_uint s2_sum = (ufbxi_fast_uint)(s2 + (s2 >> 32u)) * 8;
  2086. s2_sum += ((ufbxi_fast_uint)(s1_lo >> 0) & 0xffff) * 8;
  2087. s2_sum += ((ufbxi_fast_uint)(s1_hi >> 0) & 0xffff) * 7;
  2088. s2_sum += ((ufbxi_fast_uint)(s1_lo >> 16) & 0xffff) * 6;
  2089. s2_sum += ((ufbxi_fast_uint)(s1_hi >> 16) & 0xffff) * 5;
  2090. s2_sum += ((ufbxi_fast_uint)(s1_lo >> 32) & 0xffff) * 4;
  2091. s2_sum += ((ufbxi_fast_uint)(s1_hi >> 32) & 0xffff) * 3;
  2092. s2_sum += ((ufbxi_fast_uint)(s1_lo >> 48) & 0xffff) * 2;
  2093. s2_sum += ((ufbxi_fast_uint)(s1_hi >> 48) & 0xffff) * 1;
  2094. b += chunk_size * a;
  2095. a += s1_sum & 0xffffffffu;
  2096. b += s2_sum & 0xffffffffu;
  2097. }
  2098. #endif
  2099. while (p != end) {
  2100. a += (size_t)(uint8_t)p[0]; b += a;
  2101. p++;
  2102. }
  2103. a %= 65521u;
  2104. b %= 65521u;
  2105. }
  2106. return (uint32_t)((b << 16) | (a & 0xffff));
  2107. }
  2108. static ufbxi_noinline int
  2109. ufbxi_inflate_block_slow(ufbxi_deflate_context *dc, ufbxi_trees *trees, size_t max_symbols)
  2110. {
  2111. char *out_ptr = dc->out_ptr;
  2112. char *const out_begin = dc->out_begin;
  2113. char *const out_end = dc->out_end;
  2114. uint32_t fast_bits = trees->fast_bits;
  2115. uint32_t fast_mask = (1u << fast_bits) - 1;
  2116. uint64_t bits = dc->stream.bits;
  2117. size_t left = dc->stream.left;
  2118. const char *data = dc->stream.chunk_ptr;
  2119. for (;;) {
  2120. if (max_symbols-- == 0) break;
  2121. ufbxi_bit_refill(&bits, &left, &data, &dc->stream);
  2122. uint64_t sym_bits = bits;
  2123. ufbxi_huff_sym sym0 = ufbxi_huff_decode_bits(&trees->lit_length, bits, fast_bits, fast_mask);
  2124. ufbxi_regression_assert(sym0 != UFBXI_HUFF_UNINITIALIZED_SYM);
  2125. uint32_t sym0_bits = ufbxi_huff_sym_total_bits(sym0);
  2126. bits >>= sym0_bits;
  2127. left -= sym0_bits;
  2128. if (sym0 & UFBXI_HUFF_SYM_END) {
  2129. if (ufbxi_huff_sym_value(sym0) != 0) return -13;
  2130. dc->out_ptr = out_ptr;
  2131. dc->stream.bits = bits;
  2132. dc->stream.left = left;
  2133. dc->stream.chunk_ptr = data;
  2134. return 0;
  2135. } else if ((sym0 & UFBXI_HUFF_SYM_MATCH) == 0) {
  2136. if (out_ptr == out_end) return -10;
  2137. *out_ptr++ = (char)ufbxi_huff_sym_value(sym0);
  2138. continue;
  2139. }
  2140. uint32_t sym0_value = ufbxi_huff_sym_value(sym0);
  2141. uint32_t len_shift_base = trees->lit_length.extra_shift_base[sym0_value];
  2142. uint16_t len_mask = trees->lit_length.extra_mask[sym0_value];
  2143. uint32_t length = (len_shift_base >> 16) + (uint32_t)(ufbxi_wrap_shr64(sym_bits, len_shift_base) & len_mask);
  2144. ufbxi_huff_sym sym1 = ufbxi_huff_decode_bits(&trees->dist, bits, fast_bits, fast_mask);
  2145. ufbxi_regression_assert(sym1 != UFBXI_HUFF_UNINITIALIZED_SYM);
  2146. if (sym1 & UFBXI_HUFF_SYM_END) return -11;
  2147. uint32_t sym1_bits = ufbxi_huff_sym_total_bits(sym1);
  2148. bits >>= sym1_bits;
  2149. left -= sym1_bits;
  2150. uint32_t sym1_value = ufbxi_huff_sym_value(sym1);
  2151. uint32_t dist_shift_base = trees->dist.extra_shift_base[sym1_value];
  2152. uint16_t dist_mask = trees->dist.extra_mask[sym1_value];
  2153. uint32_t distance = (dist_shift_base >> 16) + (uint32_t)(ufbxi_wrap_shr64(sym_bits, dist_shift_base + sym0) & dist_mask);
  2154. // Bounds checking
  2155. size_t out_space = ufbxi_to_size(out_end - out_ptr);
  2156. if ((ptrdiff_t)distance > out_ptr - out_begin || length > out_space) {
  2157. return -12;
  2158. }
  2159. // Copy the match
  2160. const char *src = out_ptr - distance;
  2161. char *dst = out_ptr;
  2162. char *end = dst + length;
  2163. out_ptr += length;
  2164. if (out_space >= length + 16) {
  2165. uint32_t min_dist = length < 16 ? length : 16;
  2166. if (distance >= min_dist) {
  2167. ufbxi_copy_16_bytes(dst, src);
  2168. while (length > 16) {
  2169. src += 16;
  2170. dst += 16;
  2171. length -= 16;
  2172. ufbxi_copy_16_bytes(dst, src);
  2173. }
  2174. } else {
  2175. while (dst != end) {
  2176. *dst++ = *src++;
  2177. }
  2178. }
  2179. } else {
  2180. while (dst != end) {
  2181. *dst++ = *src++;
  2182. }
  2183. }
  2184. }
  2185. dc->out_ptr = out_ptr;
  2186. dc->stream.bits = bits;
  2187. dc->stream.left = left;
  2188. dc->stream.chunk_ptr = data;
  2189. return 1;
  2190. }
  2191. ufbx_static_assert(inflate_huff_fast_bits, UFBXI_HUFF_FAST_BITS <= 11); // `fast lit, fast len, slow dist` in 56 bits
  2192. ufbx_static_assert(inflate_huff_long_bits, UFBXI_HUFF_FAST_BITS + UFBXI_HUFF_MAX_LONG_BITS >= 15); // Largest code fits in a single long lookup
  2193. // Optimized version of `ufbxi_inflate_block_slow()`.
  2194. // Has a lot of assumptions (see asserts) and does not call _any_ (even forceinlined) functions.
  2195. static ufbxi_noinline int
  2196. ufbxi_inflate_block_fast(ufbxi_deflate_context *dc, ufbxi_trees *trees)
  2197. {
  2198. ufbxi_dev_assert(!dc->stream.cancelled);
  2199. ufbxi_dev_assert(trees->fast_bits == UFBXI_HUFF_FAST_BITS);
  2200. ufbxi_dev_assert(dc->stream.chunk_yield - dc->stream.chunk_ptr >= UFBXI_INFLATE_FAST_MIN_IN);
  2201. ufbxi_dev_assert(dc->out_end - dc->out_ptr >= UFBXI_INFLATE_FAST_MIN_OUT);
  2202. char *out_ptr = dc->out_ptr;
  2203. char *const out_begin = dc->out_begin;
  2204. char *const out_end = dc->out_end - UFBXI_INFLATE_FAST_MIN_OUT;
  2205. const ufbxi_huff_tree *tree_lit_length = &trees->lit_length;
  2206. const ufbxi_huff_tree *tree_dist = &trees->dist;
  2207. uint64_t bits = dc->stream.bits;
  2208. size_t left = dc->stream.left;
  2209. const char *data = dc->stream.chunk_ptr;
  2210. const char *data_end = dc->stream.chunk_yield - UFBXI_INFLATE_FAST_MIN_IN;
  2211. uint64_t sym01_bits;
  2212. ufbxi_huff_sym sym0, sym1;
  2213. uint64_t refill_bits = ufbxi_read_u64(data);
  2214. #define ufbxi_fast_inflate_refill_and_decode() do { \
  2215. ufbxi_macro_bit_refill_fast(bits, left, data, refill_bits); \
  2216. sym01_bits = bits; \
  2217. sym0 = tree_lit_length->fast_sym[sym01_bits & UFBXI_HUFF_FAST_MASK]; \
  2218. sym1 = ((sym0 & UFBXI_HUFF_SYM_MATCH) ? tree_dist : tree_lit_length)->fast_sym[ufbxi_wrap_shr64(sym01_bits, sym0) & UFBXI_HUFF_FAST_MASK]; \
  2219. refill_bits = ufbxi_read_u64(data); \
  2220. } while (0)
  2221. #define ufbxi_fast_inflate_should_continue() \
  2222. (((data_end - data) | (out_end - out_ptr)) >= 0)
  2223. ufbxi_fast_inflate_refill_and_decode();
  2224. for (;;) {
  2225. if ((sym0 & sym1) & UFBXI_HUFF_SYM_FAST) {
  2226. bits = ufbxi_wrap_shr64(sym01_bits, sym0 + sym1);
  2227. left -= (sym0 + sym1) & 0x3f;
  2228. if (((sym0 | sym1) & UFBXI_HUFF_SYM_MATCH) == 0) {
  2229. // Literal, Literal
  2230. // -> Output the two literals and loop back to start.
  2231. out_ptr[0] = (char)ufbxi_huff_sym_value(sym0);
  2232. out_ptr[1] = (char)ufbxi_huff_sym_value(sym1);
  2233. out_ptr += 2;
  2234. ufbxi_fast_inflate_refill_and_decode();
  2235. if (ufbxi_fast_inflate_should_continue()) continue;
  2236. break;
  2237. } else if ((sym0 & UFBXI_HUFF_SYM_MATCH) == 0) {
  2238. // Literal, Match, (Distance)
  2239. // -> Output a single literal, decode the missing distance and fall through to match.
  2240. out_ptr[0] = (char)ufbxi_huff_sym_value(sym0);
  2241. out_ptr += 1;
  2242. sym01_bits = ufbxi_wrap_shr64(sym01_bits, sym0);
  2243. // This must fit as literals never have extra bits and the match length is fast so:
  2244. // 10 (lit) + 10 (len code) + 5 (len extra) + 15 (dist code) + 13 (dist extra) = 53 <= 56
  2245. sym0 = sym1;
  2246. sym1 = tree_dist->fast_sym[bits & UFBXI_HUFF_FAST_MASK];
  2247. if ((sym1 & UFBXI_HUFF_SYM_FAST) == 0) {
  2248. // Slow sym1
  2249. if (sym1 & UFBXI_HUFF_SYM_END) return -11;
  2250. uint32_t tail = (uint32_t)(bits >> UFBXI_HUFF_FAST_BITS);
  2251. uint32_t long_mask = ufbxi_huff_sym_long_mask(sym1);
  2252. sym1 = tree_dist->long_sym[ufbxi_huff_sym_long_offset(sym1) + (tail & long_mask)];
  2253. if (sym1 & UFBXI_HUFF_SYM_END) return -11;
  2254. }
  2255. bits = ufbxi_wrap_shr64(bits, sym1);
  2256. left -= sym1 & 0x3f;
  2257. } else {
  2258. // Match, Distance
  2259. // -> Fall through to match copy.
  2260. }
  2261. } else {
  2262. if ((sym0 & (UFBXI_HUFF_SYM_FAST|UFBXI_HUFF_SYM_END)) == 0) {
  2263. // Slow sym0
  2264. uint32_t tail = (uint32_t)(sym01_bits >> UFBXI_HUFF_FAST_BITS);
  2265. uint32_t long_mask = ufbxi_huff_sym_long_mask(sym0);
  2266. sym0 = tree_lit_length->long_sym[ufbxi_huff_sym_long_offset(sym0) + (tail & long_mask)];
  2267. }
  2268. uint32_t sym0_bits = ufbxi_huff_sym_total_bits(sym0);
  2269. bits >>= sym0_bits;
  2270. left -= sym0_bits;
  2271. if (sym0 & UFBXI_HUFF_SYM_END) {
  2272. if (ufbxi_huff_sym_value(sym0) != 0) return -13;
  2273. dc->out_ptr = out_ptr;
  2274. dc->stream.bits = bits;
  2275. dc->stream.left = left;
  2276. dc->stream.chunk_ptr = data;
  2277. return 0;
  2278. }
  2279. if (sym0 & UFBXI_HUFF_SYM_MATCH) {
  2280. sym1 = tree_dist->fast_sym[bits & UFBXI_HUFF_FAST_MASK];
  2281. if ((sym1 & UFBXI_HUFF_SYM_FAST) == 0) {
  2282. // Slow sym1
  2283. if (sym1 & UFBXI_HUFF_SYM_END) return -11;
  2284. uint32_t tail = (uint32_t)(bits >> UFBXI_HUFF_FAST_BITS);
  2285. uint32_t long_mask = ufbxi_huff_sym_long_mask(sym1);
  2286. sym1 = tree_dist->long_sym[ufbxi_huff_sym_long_offset(sym1) + (tail & long_mask)];
  2287. if (sym1 & UFBXI_HUFF_SYM_END) return -11;
  2288. }
  2289. bits = ufbxi_wrap_shr64(bits, sym1);
  2290. left -= sym1 & 0x3f;
  2291. } else {
  2292. *out_ptr++ = (char)ufbxi_huff_sym_value(sym0);
  2293. ufbxi_fast_inflate_refill_and_decode();
  2294. if (ufbxi_fast_inflate_should_continue()) continue;
  2295. break;
  2296. }
  2297. }
  2298. uint32_t sym0_value = ufbxi_huff_sym_value(sym0);
  2299. uint32_t len_shift_base = trees->lit_length.extra_shift_base[sym0_value];
  2300. uint16_t len_mask = trees->lit_length.extra_mask[sym0_value];
  2301. uint32_t length = (len_shift_base >> 16) + (uint32_t)(ufbxi_wrap_shr64(sym01_bits, len_shift_base) & len_mask);
  2302. uint32_t sym1_value = ufbxi_huff_sym_value(sym1);
  2303. uint32_t dist_shift_base = trees->dist.extra_shift_base[sym1_value];
  2304. uint16_t dist_mask = trees->dist.extra_mask[sym1_value];
  2305. uint32_t distance = (dist_shift_base >> 16) + (uint32_t)(ufbxi_wrap_shr64(sym01_bits, dist_shift_base + sym0) & dist_mask);
  2306. ufbxi_fast_inflate_refill_and_decode();
  2307. // Bounds checking: We don't actually handle the error here, just bail out to the slow implementation
  2308. ptrdiff_t dst_space = out_end - out_ptr - (ptrdiff_t)length + UFBXI_INFLATE_FAST_MIN_OUT;
  2309. ptrdiff_t src_space = out_ptr - out_begin - (ptrdiff_t)distance;
  2310. if ((dst_space | src_space) < 0) {
  2311. return -12;
  2312. }
  2313. const char *src = out_ptr - distance;
  2314. char *dst = out_ptr;
  2315. char *end = dst + length;
  2316. out_ptr += length;
  2317. // Copy the match
  2318. uint32_t min_dist = length < 16 ? length : 16;
  2319. if (distance >= min_dist && dst_space >= 16) {
  2320. ufbxi_copy_16_bytes(dst, src);
  2321. while (length > 16) {
  2322. src += 16;
  2323. dst += 16;
  2324. length -= 16;
  2325. ufbxi_copy_16_bytes(dst, src);
  2326. }
  2327. } else {
  2328. while (dst != end) {
  2329. *dst++ = *src++;
  2330. }
  2331. }
  2332. if (ufbxi_fast_inflate_should_continue()) continue;
  2333. break;
  2334. }
  2335. dc->out_ptr = out_ptr;
  2336. dc->stream.bits = bits;
  2337. dc->stream.left = left;
  2338. dc->stream.chunk_ptr = data;
  2339. return 1;
  2340. #undef ufbxi_fast_inflate_refill_and_decode
  2341. #undef ufbxi_fast_inflate_should_continue
  2342. }
  2343. static void ufbxi_inflate_init_retain(ufbx_inflate_retain *retain)
  2344. {
  2345. ufbxi_inflate_retain_imp *ret_imp = (ufbxi_inflate_retain_imp*)retain;
  2346. if (!ret_imp->initialized) {
  2347. ufbxi_init_static_huff(&ret_imp->static_trees, NULL);
  2348. ret_imp->initialized = true;
  2349. }
  2350. }
  2351. // TODO: Error codes should have a quick test if the destination buffer overflowed
  2352. // Returns actual number of decompressed bytes or negative error:
  2353. // -1: Bad compression method (ZLIB header)
  2354. // -2: Requires dictionary (ZLIB header)
  2355. // -3: Bad FCHECK (ZLIB header)
  2356. // -4: Bad NLEN (Uncompressed LEN != ~NLEN)
  2357. // -5: Uncompressed source overflow
  2358. // -6: Uncompressed destination overflow
  2359. // -7: Bad block type
  2360. // -8: Truncated checksum (deprecated, reported as -9)
  2361. // -9: Checksum mismatch
  2362. // -10: Literal destination overflow
  2363. // -11: Bad distance code or distance of (30..31)
  2364. // -12: Match out of bounds
  2365. // -13: Bad lit/length code
  2366. // -14: Codelen Huffman Overfull
  2367. // -15: Codelen Huffman Underfull
  2368. // -16 - -21: Litlen Huffman: Overfull / Underfull / Repeat 16/17/18 overflow / Bad length code
  2369. // -22 - -27: Distance Huffman: Overfull / Underfull / Repeat 16/17/18 overflow / Bad length code
  2370. // -28: Cancelled
  2371. // -29: Invalid ufbx_inflate_input.internal_fast_bits value
  2372. ufbxi_extern_c ptrdiff_t ufbx_inflate(void *dst, size_t dst_size, const ufbx_inflate_input *input, ufbx_inflate_retain *retain)
  2373. {
  2374. ufbxi_inflate_retain_imp *ret_imp = (ufbxi_inflate_retain_imp*)retain;
  2375. ptrdiff_t err;
  2376. ufbxi_deflate_context dc;
  2377. ufbxi_bit_stream_init(&dc.stream, input);
  2378. dc.out_begin = (char*)dst;
  2379. dc.out_ptr = (char*)dst;
  2380. dc.out_end = (char*)dst + dst_size;
  2381. if (input->internal_fast_bits != 0) {
  2382. dc.fast_bits = (uint32_t)input->internal_fast_bits;
  2383. if (dc.fast_bits < 1 || dc.fast_bits == 9 || dc.fast_bits > 10) return -29;
  2384. } else {
  2385. // TODO: Profile this
  2386. dc.fast_bits = input->total_size > 2048 ? 10 : 8;
  2387. }
  2388. uint64_t bits = dc.stream.bits;
  2389. size_t left = dc.stream.left;
  2390. const char *data = dc.stream.chunk_ptr;
  2391. ufbxi_bit_refill(&bits, &left, &data, &dc.stream);
  2392. if (dc.stream.cancelled) return -28;
  2393. // Zlib header
  2394. if (!input->no_header) {
  2395. size_t cmf = (size_t)(bits & 0xff);
  2396. size_t flg = (size_t)(bits >> 8) & 0xff;
  2397. bits >>= 16;
  2398. left -= 16;
  2399. if ((cmf & 0xf) != 0x8) return -1;
  2400. if ((flg & 0x20) != 0) return -2;
  2401. if ((cmf << 8 | flg) % 31u != 0) return -3;
  2402. }
  2403. for (;;) {
  2404. ufbxi_bit_refill(&bits, &left, &data, &dc.stream);
  2405. if (dc.stream.cancelled) return -28;
  2406. // Block header: [0:1] BFINAL [1:3] BTYPE
  2407. size_t header = (size_t)bits & 0x7;
  2408. bits >>= 3;
  2409. left -= 3;
  2410. size_t type = header >> 1;
  2411. if (type == 0) {
  2412. // Round up to the next byte
  2413. size_t align_bits = left & 0x7;
  2414. bits >>= align_bits;
  2415. left -= align_bits;
  2416. size_t len = (size_t)(bits & 0xffff);
  2417. size_t nlen = (size_t)((bits >> 16) & 0xffff);
  2418. if ((len ^ nlen) != 0xffff) return -4;
  2419. if (dc.out_end - dc.out_ptr < (ptrdiff_t)len) return -6;
  2420. bits >>= 32;
  2421. left -= 32;
  2422. dc.stream.bits = bits;
  2423. dc.stream.left = left;
  2424. dc.stream.chunk_ptr = data;
  2425. // Copy `len` bytes of literal data
  2426. if (!ufbxi_bit_copy_bytes(dc.out_ptr, &dc.stream, len)) return -5;
  2427. dc.out_ptr += len;
  2428. } else if (type <= 2) {
  2429. dc.stream.bits = bits;
  2430. dc.stream.left = left;
  2431. dc.stream.chunk_ptr = data;
  2432. ufbxi_trees tree_data; // ufbxi_uninit
  2433. ufbxi_trees *trees; // ufbxi_uninit
  2434. if (type == 1) {
  2435. // Static Huffman: Initialize the trees once and cache them in `retain`.
  2436. if (!ret_imp->initialized) {
  2437. ufbxi_init_static_huff(&ret_imp->static_trees, input);
  2438. ret_imp->initialized = true;
  2439. }
  2440. trees = &ret_imp->static_trees;
  2441. } else {
  2442. // Dynamic Huffman
  2443. err = ufbxi_init_dynamic_huff(&dc, &tree_data);
  2444. if (err) return err;
  2445. trees = &tree_data;
  2446. }
  2447. for (;;) {
  2448. bool fast_viable = trees->fast_bits == UFBXI_HUFF_FAST_BITS && dc.out_end - dc.out_ptr >= UFBXI_INFLATE_FAST_MIN_OUT;
  2449. // `ufbxi_inflate_block_fast()` needs a bit more upfront setup, see asserts on top of the function
  2450. if (fast_viable && dc.stream.chunk_yield - dc.stream.chunk_ptr >= UFBXI_INFLATE_FAST_MIN_IN) {
  2451. err = ufbxi_inflate_block_fast(&dc, trees);
  2452. } else {
  2453. err = ufbxi_inflate_block_slow(&dc, trees, fast_viable ? 32 : SIZE_MAX);
  2454. }
  2455. if (err < 0) return err;
  2456. // `ufbxi_inflate_block()` returns normally on cancel so check it here
  2457. if (dc.stream.cancelled) return -28;
  2458. if (err == 0) break;
  2459. }
  2460. } else {
  2461. // 0b11 - reserved (error)
  2462. return -7;
  2463. }
  2464. bits = dc.stream.bits;
  2465. left = dc.stream.left;
  2466. data = dc.stream.chunk_ptr;
  2467. // BFINAL: End of stream
  2468. if (header & 1) break;
  2469. }
  2470. // Check Adler-32
  2471. {
  2472. // Round up to the next byte
  2473. size_t align_bits = left & 0x7;
  2474. bits >>= align_bits;
  2475. left -= align_bits;
  2476. ufbxi_bit_refill(&bits, &left, &data, &dc.stream);
  2477. if (dc.stream.cancelled) return -28;
  2478. if (!input->no_checksum) {
  2479. uint32_t ref = (uint32_t)bits;
  2480. ref = (ref>>24) | ((ref>>8)&0xff00) | ((ref<<8)&0xff0000) | (ref<<24);
  2481. uint32_t checksum = ufbxi_adler32(dc.out_begin, ufbxi_to_size(dc.out_ptr - dc.out_begin));
  2482. if (ref != checksum) {
  2483. return -9;
  2484. }
  2485. }
  2486. }
  2487. return dc.out_ptr - dc.out_begin;
  2488. }
  2489. #endif // !defined(ufbx_inflate)
  2490. // -- Errors
  2491. static const char ufbxi_empty_char[1] = { '\0' };
  2492. static ufbxi_noinline int ufbxi_vsnprintf(char *buf, size_t buf_size, const char *fmt, va_list args)
  2493. {
  2494. int result = vsnprintf(buf, buf_size, fmt, args);
  2495. if (result < 0) result = 0;
  2496. if ((size_t)result >= buf_size - 1) result = (int)buf_size - 1;
  2497. // HACK: On some MSYS/MinGW implementations `vsnprintf` is broken and does
  2498. // not write the null terminator on truncation, it's always safe to do so
  2499. // let's just do it unconditionally here...
  2500. buf[result] = '\0';
  2501. return result;
  2502. }
  2503. static ufbxi_noinline int ufbxi_snprintf(char *buf, size_t buf_size, const char *fmt, ...)
  2504. {
  2505. va_list args; // ufbxi_uninit
  2506. va_start(args, fmt);
  2507. int result = ufbxi_vsnprintf(buf, buf_size, fmt, args);
  2508. va_end(args);
  2509. return result;
  2510. }
  2511. static ufbxi_noinline void ufbxi_panicf_imp(ufbx_panic *panic, const char *fmt, ...)
  2512. {
  2513. if (panic && panic->did_panic) return;
  2514. va_list args; // ufbxi_uninit
  2515. va_start(args, fmt);
  2516. if (panic) {
  2517. panic->did_panic = true;
  2518. panic->message_length = (size_t)ufbxi_vsnprintf(panic->message, sizeof(panic->message), fmt, args);
  2519. } else {
  2520. fprintf(stderr, "ufbx panic: ");
  2521. vfprintf(stderr, fmt, args);
  2522. fprintf(stderr, "\n");
  2523. }
  2524. va_end(args);
  2525. if (!panic) {
  2526. ufbx_assert(false && "ufbx panic: See stderr for more information");
  2527. }
  2528. }
  2529. #define ufbxi_panicf(panic, cond, ...) \
  2530. ((cond) ? false : (ufbxi_panicf_imp((panic), __VA_ARGS__), true))
  2531. // Prefix the error condition with $Description\0 for a human readable description
  2532. #define ufbxi_error_msg(cond, msg) "$" msg "\0" cond
  2533. static ufbxi_noinline int ufbxi_fail_imp_err(ufbx_error *err, const char *cond, const char *func, uint32_t line)
  2534. {
  2535. if (cond[0] == '$') {
  2536. if (!err->description.data) {
  2537. err->description.data = cond + 1;
  2538. err->description.length = strlen(err->description.data);
  2539. }
  2540. #if UFBXI_FEATURE_ERROR_STACK
  2541. // Skip the description part if adding to a stack
  2542. cond = cond + strlen(cond) + 1;
  2543. #endif
  2544. }
  2545. // NOTE: This is the base function all fails boil down to, place a breakpoint here to
  2546. // break at the first error
  2547. #if UFBXI_FEATURE_ERROR_STACK
  2548. if (err->stack_size < UFBX_ERROR_STACK_MAX_DEPTH) {
  2549. ufbx_error_frame *frame = &err->stack[err->stack_size++];
  2550. frame->description.data = cond;
  2551. frame->description.length = strlen(cond);
  2552. frame->function.data = func;
  2553. frame->function.length = strlen(func);
  2554. frame->source_line = line;
  2555. }
  2556. #else
  2557. ufbxi_ignore(func);
  2558. ufbxi_ignore(line);
  2559. #endif
  2560. return 0;
  2561. }
  2562. ufbxi_nodiscard static ufbxi_noinline size_t ufbxi_utf8_valid_length(const char *str, size_t length)
  2563. {
  2564. size_t index = 0;
  2565. while (index < length) {
  2566. uint8_t c = (uint8_t)str[index];
  2567. size_t left = length - index;
  2568. if ((c & 0x80) == 0) {
  2569. if (c != 0) {
  2570. index += 1;
  2571. continue;
  2572. }
  2573. } else if ((c & 0xe0) == 0xc0 && left >= 2) {
  2574. uint8_t t0 = (uint8_t)str[index + 1];
  2575. uint32_t code = (uint32_t)c << 8 | (uint32_t)t0;
  2576. if ((code & 0xc0) == 0x80 && code >= 0xc280) {
  2577. index += 2;
  2578. continue;
  2579. }
  2580. } else if ((c & 0xf0) == 0xe0 && left >= 3) {
  2581. uint8_t t0 = (uint8_t)str[index + 1], t1 = (uint8_t)str[index + 2];
  2582. uint32_t code = (uint32_t)c << 16 | (uint32_t)t0 << 8 | (uint32_t)t1;
  2583. if ((code & 0xc0c0) == 0x8080 && code >= 0xe0a080 && (code < 0xeda080 || code >= 0xee8080)) {
  2584. index += 3;
  2585. continue;
  2586. }
  2587. } else if ((c & 0xf8) == 0xf0 && left >= 4) {
  2588. uint8_t t0 = (uint8_t)str[index + 1], t1 = (uint8_t)str[index + 2], t2 = (uint8_t)str[index + 3];
  2589. uint32_t code = (uint32_t)c << 24 | (uint32_t)t0 << 16 | (uint32_t)t1 << 8 | (uint32_t)t2;
  2590. if ((code & 0xc0c0c0) == 0x808080 && code >= 0xf0908080u && code <= 0xf48fbfbfu) {
  2591. index += 4;
  2592. continue;
  2593. }
  2594. }
  2595. break;
  2596. }
  2597. ufbx_assert(index <= length);
  2598. return index;
  2599. }
  2600. static ufbxi_noinline void ufbxi_clean_string_utf8(char *str, size_t length)
  2601. {
  2602. size_t pos = 0;
  2603. for (;;) {
  2604. pos += ufbxi_utf8_valid_length(str + pos, length);
  2605. if (pos == length) break;
  2606. str[pos++] = '?';
  2607. }
  2608. }
  2609. static ufbxi_noinline void ufbxi_set_err_info(ufbx_error *err, const char *data, size_t length)
  2610. {
  2611. if (!err) return;
  2612. if (length == SIZE_MAX) length = strlen(data);
  2613. size_t to_copy = ufbxi_min_sz(sizeof(err->info) - 1, length);
  2614. memcpy(err->info, data, to_copy);
  2615. err->info[to_copy] = '\0';
  2616. err->info_length = to_copy;
  2617. ufbxi_clean_string_utf8(err->info, err->info_length);
  2618. }
  2619. static ufbxi_noinline void ufbxi_fmt_err_info(ufbx_error *err, const char *fmt, ...)
  2620. {
  2621. if (!err) return;
  2622. va_list args; // ufbxi_uninit
  2623. va_start(args, fmt);
  2624. err->info_length = (size_t)ufbxi_vsnprintf(err->info, sizeof(err->info), fmt, args);
  2625. va_end(args);
  2626. ufbxi_clean_string_utf8(err->info, err->info_length);
  2627. }
  2628. static ufbxi_noinline void ufbxi_clear_error(ufbx_error *err)
  2629. {
  2630. if (!err) return;
  2631. err->type = UFBX_ERROR_NONE;
  2632. err->description.data = ufbxi_empty_char;
  2633. err->description.length = 0;
  2634. err->stack_size = 0;
  2635. err->info[0] = '\0';
  2636. err->info_length = 0;
  2637. }
  2638. #if UFBXI_FEATURE_ERROR_STACK
  2639. #define ufbxi_function __FUNCTION__
  2640. #define ufbxi_line __LINE__
  2641. #define ufbxi_cond_str(cond) #cond
  2642. #else
  2643. #define ufbxi_function ""
  2644. #define ufbxi_line 0
  2645. #define ufbxi_cond_str(cond) ""
  2646. #endif
  2647. #define ufbxi_check_err(err, cond) do { if (ufbxi_unlikely(!ufbxi_trace(cond))) { ufbxi_fail_imp_err((err), ufbxi_cond_str(cond), ufbxi_function, ufbxi_line); return 0; } } while (0)
  2648. #define ufbxi_check_return_err(err, cond, ret) do { if (ufbxi_unlikely(!ufbxi_trace(cond))) { ufbxi_fail_imp_err((err), ufbxi_cond_str(cond), ufbxi_function, ufbxi_line); return ret; } } while (0)
  2649. #define ufbxi_fail_err(err, desc) return ufbxi_fail_imp_err(err, desc, ufbxi_function, ufbxi_line)
  2650. #define ufbxi_check_err_msg(err, cond, msg) do { if (ufbxi_unlikely(!ufbxi_trace(cond))) { ufbxi_fail_imp_err((err), ufbxi_error_msg(ufbxi_cond_str(cond), msg), ufbxi_function, ufbxi_line); return 0; } } while (0)
  2651. #define ufbxi_check_return_err_msg(err, cond, ret, msg) do { if (ufbxi_unlikely(!ufbxi_trace(cond))) { ufbxi_fail_imp_err((err), ufbxi_error_msg(ufbxi_cond_str(cond), msg), ufbxi_function, ufbxi_line); return ret; } } while (0)
  2652. #define ufbxi_fail_err_msg(err, desc, msg) return ufbxi_fail_imp_err(err, ufbxi_error_msg(desc, msg), ufbxi_function, ufbxi_line)
  2653. #define ufbxi_report_err_msg(err, desc, msg) (void)ufbxi_fail_imp_err(err, ufbxi_error_msg(desc, msg), ufbxi_function, ufbxi_line)
  2654. static ufbxi_noinline void ufbxi_fix_error_type(ufbx_error *error, const char *default_desc)
  2655. {
  2656. const char *desc = error->description.data;
  2657. if (!desc) desc = default_desc;
  2658. error->type = UFBX_ERROR_UNKNOWN;
  2659. if (!strcmp(desc, "Out of memory")) {
  2660. error->type = UFBX_ERROR_OUT_OF_MEMORY;
  2661. } else if (!strcmp(desc, "Memory limit exceeded")) {
  2662. error->type = UFBX_ERROR_MEMORY_LIMIT;
  2663. } else if (!strcmp(desc, "Allocation limit exceeded")) {
  2664. error->type = UFBX_ERROR_ALLOCATION_LIMIT;
  2665. } else if (!strcmp(desc, "Truncated file")) {
  2666. error->type = UFBX_ERROR_TRUNCATED_FILE;
  2667. } else if (!strcmp(desc, "IO error")) {
  2668. error->type = UFBX_ERROR_IO;
  2669. } else if (!strcmp(desc, "Cancelled")) {
  2670. error->type = UFBX_ERROR_CANCELLED;
  2671. } else if (!strcmp(desc, "Unrecognized file format")) {
  2672. error->type = UFBX_ERROR_UNRECOGNIZED_FILE_FORMAT;
  2673. } else if (!strcmp(desc, "File not found")) {
  2674. error->type = UFBX_ERROR_FILE_NOT_FOUND;
  2675. } else if (!strcmp(desc, "Empty file")) {
  2676. error->type = UFBX_ERROR_EMPTY_FILE;
  2677. } else if (!strcmp(desc, "External file not found")) {
  2678. error->type = UFBX_ERROR_EXTERNAL_FILE_NOT_FOUND;
  2679. } else if (!strcmp(desc, "Uninitialized options")) {
  2680. error->type = UFBX_ERROR_UNINITIALIZED_OPTIONS;
  2681. } else if (!strcmp(desc, "Zero vertex size")) {
  2682. error->type = UFBX_ERROR_ZERO_VERTEX_SIZE;
  2683. } else if (!strcmp(desc, "Truncated vertex stream")) {
  2684. error->type = UFBX_ERROR_TRUNCATED_VERTEX_STREAM;
  2685. } else if (!strcmp(desc, "Invalid UTF-8")) {
  2686. error->type = UFBX_ERROR_INVALID_UTF8;
  2687. } else if (!strcmp(desc, "Feature disabled")) {
  2688. error->type = UFBX_ERROR_FEATURE_DISABLED;
  2689. } else if (!strcmp(desc, "Bad NURBS geometry")) {
  2690. error->type = UFBX_ERROR_BAD_NURBS;
  2691. } else if (!strcmp(desc, "Bad index")) {
  2692. error->type = UFBX_ERROR_BAD_INDEX;
  2693. } else if (!strcmp(desc, "Node depth limit exceeded")) {
  2694. error->type = UFBX_ERROR_NODE_DEPTH_LIMIT;
  2695. } else if (!strcmp(desc, "Threaded ASCII parse error")) {
  2696. error->type = UFBX_ERROR_THREADED_ASCII_PARSE;
  2697. } else if (!strcmp(desc, "Unsafe options")) {
  2698. error->type = UFBX_ERROR_UNSAFE_OPTIONS;
  2699. } else if (!strcmp(desc, "Duplicate override")) {
  2700. error->type = UFBX_ERROR_DUPLICATE_OVERRIDE;
  2701. }
  2702. error->description.data = desc;
  2703. error->description.length = strlen(desc);
  2704. }
  2705. // -- Allocator
  2706. // Returned for zero size allocations, place in the constant data
  2707. // to catch writes to bad allocations.
  2708. #if defined(UFBX_REGRESSION)
  2709. static const char ufbxi_zero_size_buffer[4096] = { 0 };
  2710. #else
  2711. static const char ufbxi_zero_size_buffer[64] = { 0 };
  2712. #endif
  2713. static ufbxi_forceinline size_t ufbxi_align_to_mask(size_t value, size_t align_mask)
  2714. {
  2715. return value + (((size_t)0 - value) & align_mask);
  2716. }
  2717. static ufbxi_forceinline size_t ufbxi_size_align_mask(size_t size)
  2718. {
  2719. // Align to the all bits below the lowest set one in `size`
  2720. // up to a maximum of 0x7 (align to 8 bytes).
  2721. return ((size ^ (size - 1)) >> 1) & 0x7;
  2722. }
  2723. typedef struct {
  2724. ufbx_error *error;
  2725. size_t current_size;
  2726. size_t max_size;
  2727. size_t num_allocs;
  2728. size_t max_allocs;
  2729. size_t huge_size;
  2730. size_t chunk_max;
  2731. ufbx_allocator_opts ator;
  2732. const char *name;
  2733. } ufbxi_allocator;
  2734. static ufbxi_forceinline bool ufbxi_does_overflow(size_t total, size_t a, size_t b)
  2735. {
  2736. // If `a` and `b` have at most 4 bits per `size_t` byte, the product can't overflow.
  2737. if (((a | b) >> sizeof(size_t)*4) != 0) {
  2738. if (a != 0 && total / a != b) return true;
  2739. }
  2740. return false;
  2741. }
  2742. static ufbxi_noinline void *ufbxi_alloc_size(ufbxi_allocator *ator, size_t size, size_t n)
  2743. {
  2744. // Always succeed with an empty non-NULL buffer for empty allocations
  2745. ufbx_assert(size > 0);
  2746. if (n == 0) return (void*)ufbxi_zero_size_buffer;
  2747. size_t total = size * n;
  2748. ufbxi_check_return_err(ator->error, !ufbxi_does_overflow(total, size, n), NULL);
  2749. ufbxi_check_return_err(ator->error, total <= SIZE_MAX / 2, NULL); // Make sure it's always safe to double allocations
  2750. if (!(total < ator->max_size - ator->current_size)) {
  2751. ufbxi_report_err_msg(ator->error, "total <= ator->max_size - ator->current_size", "Memory limit exceeded");
  2752. ufbxi_fmt_err_info(ator->error, "%s", ator->name);
  2753. return NULL;
  2754. }
  2755. if (!(ator->num_allocs < ator->max_allocs)) {
  2756. ufbxi_report_err_msg(ator->error, "ator->num_allocs < ator->max_allocs", "Allocation limit exceeded");
  2757. ufbxi_fmt_err_info(ator->error, "%s", ator->name);
  2758. return NULL;
  2759. }
  2760. ator->num_allocs++;
  2761. void *ptr;
  2762. if (ator->ator.allocator.alloc_fn) {
  2763. ptr = ator->ator.allocator.alloc_fn(ator->ator.allocator.user, total);
  2764. } else if (ator->ator.allocator.realloc_fn) {
  2765. ptr = ator->ator.allocator.realloc_fn(ator->ator.allocator.user, NULL, 0, total);
  2766. } else {
  2767. ptr = malloc(total);
  2768. }
  2769. if (!ptr) {
  2770. ufbxi_report_err_msg(ator->error, "ptr", "Out of memory");
  2771. ufbxi_fmt_err_info(ator->error, "%s", ator->name);
  2772. return NULL;
  2773. }
  2774. ufbx_assert(((uintptr_t)ptr & ufbxi_size_align_mask(total)) == 0);
  2775. ator->current_size += total;
  2776. return ptr;
  2777. }
  2778. static void ufbxi_free_size(ufbxi_allocator *ator, size_t size, void *ptr, size_t n);
  2779. static ufbxi_noinline void *ufbxi_realloc_size(ufbxi_allocator *ator, size_t size, void *old_ptr, size_t old_n, size_t n)
  2780. {
  2781. ufbx_assert(size > 0);
  2782. // realloc() with zero old/new size is equivalent to alloc()/free()
  2783. if (old_n == 0) return ufbxi_alloc_size(ator, size, n);
  2784. if (n == 0) { ufbxi_free_size(ator, size, old_ptr, old_n); return NULL; }
  2785. size_t old_total = size * old_n;
  2786. size_t total = size * n;
  2787. // The old values have been checked by a previous allocate call
  2788. ufbx_assert(!ufbxi_does_overflow(old_total, size, old_n));
  2789. ufbx_assert(old_total <= ator->current_size);
  2790. ufbxi_check_return_err(ator->error, !ufbxi_does_overflow(total, size, n), NULL);
  2791. ufbxi_check_return_err(ator->error, total <= SIZE_MAX / 2, NULL); // Make sure it's always safe to double allocations
  2792. ufbxi_check_return_err_msg(ator->error, total <= ator->max_size - ator->current_size, NULL, "Memory limit exceeded");
  2793. ufbxi_check_return_err_msg(ator->error, ator->num_allocs < ator->max_allocs, NULL, "Allocation limit exceeded");
  2794. ator->num_allocs++;
  2795. void *ptr;
  2796. if (ator->ator.allocator.realloc_fn) {
  2797. ptr = ator->ator.allocator.realloc_fn(ator->ator.allocator.user, old_ptr, old_total, total);
  2798. } else if (ator->ator.allocator.alloc_fn) {
  2799. // Use user-provided alloc_fn() and free_fn()
  2800. ptr = ator->ator.allocator.alloc_fn(ator->ator.allocator.user, total);
  2801. if (ptr) memcpy(ptr, old_ptr, old_total);
  2802. if (ator->ator.allocator.free_fn) {
  2803. ator->ator.allocator.free_fn(ator->ator.allocator.user, old_ptr, old_total);
  2804. }
  2805. } else {
  2806. ptr = realloc(old_ptr, total);
  2807. }
  2808. ufbxi_check_return_err_msg(ator->error, ptr, NULL, "Out of memory");
  2809. ufbx_assert(((uintptr_t)ptr & ufbxi_size_align_mask(total)) == 0);
  2810. ator->current_size += total;
  2811. ator->current_size -= old_total;
  2812. return ptr;
  2813. }
  2814. static ufbxi_noinline void ufbxi_free_size(ufbxi_allocator *ator, size_t size, void *ptr, size_t n)
  2815. {
  2816. ufbx_assert(size > 0);
  2817. if (n == 0) return;
  2818. ufbx_assert(ptr);
  2819. size_t total = size * n;
  2820. // The old values have been checked by a previous allocate call
  2821. ufbx_assert(!ufbxi_does_overflow(total, size, n));
  2822. ufbx_assert(total <= ator->current_size);
  2823. ator->current_size -= total;
  2824. if (ator->ator.allocator.alloc_fn || ator->ator.allocator.realloc_fn) {
  2825. // Don't call default free() if there is an user-provided `alloc_fn()`
  2826. if (ator->ator.allocator.free_fn) {
  2827. ator->ator.allocator.free_fn(ator->ator.allocator.user, ptr, total);
  2828. } else if (ator->ator.allocator.realloc_fn) {
  2829. ator->ator.allocator.realloc_fn(ator->ator.allocator.user, ptr, total, 0);
  2830. }
  2831. } else {
  2832. free(ptr);
  2833. }
  2834. }
  2835. ufbxi_noinline ufbxi_nodiscard static bool ufbxi_grow_array_size(ufbxi_allocator *ator, size_t size, void *p_ptr, size_t *p_cap, size_t n)
  2836. {
  2837. #if defined(UFBX_REGRESSION)
  2838. {
  2839. ufbxi_check_return_err_msg(ator->error, ator->num_allocs < ator->max_allocs, false, "Allocation limit exceeded");
  2840. ator->num_allocs++;
  2841. }
  2842. #endif
  2843. if (n <= *p_cap) return true;
  2844. void *ptr = *(void**)p_ptr;
  2845. size_t old_n = *p_cap;
  2846. if (old_n >= n) return true;
  2847. size_t new_n = ufbxi_max_sz(old_n * 2, n);
  2848. void *new_ptr = ufbxi_realloc_size(ator, size, ptr, old_n, new_n);
  2849. if (!new_ptr) return false;
  2850. *(void**)p_ptr = new_ptr;
  2851. *p_cap = new_n;
  2852. return true;
  2853. }
  2854. static ufbxi_noinline void ufbxi_free_ator(ufbxi_allocator *ator)
  2855. {
  2856. ufbx_assert(ator->current_size == 0);
  2857. ufbx_free_allocator_fn *free_fn = ator->ator.allocator.free_allocator_fn;
  2858. if (free_fn) {
  2859. void *user = ator->ator.allocator.user;
  2860. free_fn(user);
  2861. }
  2862. }
  2863. #define ufbxi_alloc(ator, type, n) ufbxi_maybe_null((type*)ufbxi_alloc_size((ator), sizeof(type), (n)))
  2864. #define ufbxi_alloc_zero(ator, type, n) ufbxi_maybe_null((type*)ufbxi_alloc_zero_size((ator), sizeof(type), (n)))
  2865. #define ufbxi_realloc(ator, type, old_ptr, old_n, n) ufbxi_maybe_null((type*)ufbxi_realloc_size((ator), sizeof(type), (old_ptr), (old_n), (n)))
  2866. #define ufbxi_realloc_zero(ator, type, old_ptr, old_n, n) ufbxi_maybe_null((type*)ufbxi_realloc_zero_size((ator), sizeof(type), (old_ptr), (old_n), (n)))
  2867. #define ufbxi_free(ator, type, ptr, n) ufbxi_free_size((ator), sizeof(type), (ptr), (n))
  2868. #define ufbxi_grow_array(ator, p_ptr, p_cap, n) ufbxi_grow_array_size((ator), sizeof(**(p_ptr)), (p_ptr), (p_cap), (n))
  2869. #define UFBXI_SCENE_IMP_MAGIC 0x58424655
  2870. #define UFBXI_MESH_IMP_MAGIC 0x48534d55
  2871. #define UFBXI_LINE_CURVE_IMP_MAGIC 0x55434c55
  2872. #define UFBXI_CACHE_IMP_MAGIC 0x48434355
  2873. #define UFBXI_ANIM_IMP_MAGIC 0x494e4155
  2874. #define UFBXI_BAKED_ANIM_IMP_MAGIC 0x4b414255
  2875. #define UFBXI_REFCOUNT_IMP_MAGIC 0x46455255
  2876. #define UFBXI_BUF_CHUNK_IMP_MAGIC 0x46554255
  2877. // -- Memory buffer
  2878. //
  2879. // General purpose memory buffer that can be used either as a chunked linear memory
  2880. // allocator or a non-contiguous stack. You can convert the contents of `ufbxi_buf`
  2881. // to a contiguous range of memory by calling `ufbxi_make_array[_all]()`
  2882. typedef struct ufbxi_buf_padding ufbxi_buf_padding;
  2883. typedef struct ufbxi_buf_chunk ufbxi_buf_chunk;
  2884. struct ufbxi_buf_padding {
  2885. size_t original_pos; // < Original position before aligning
  2886. size_t prev_padding; // < Starting offset of the previous `ufbxi_buf_padding`
  2887. };
  2888. struct ufbxi_buf_chunk {
  2889. // Linked list of nodes
  2890. ufbxi_buf_chunk *root;
  2891. ufbxi_buf_chunk *prev;
  2892. ufbxi_buf_chunk *next;
  2893. union {
  2894. size_t magic; // < Magic for debugging
  2895. void *align_0; // < Align to 4x pointer size (16/32 bytes)
  2896. };
  2897. size_t size; // < Size of the chunk `data`, excluding this header
  2898. size_t pushed_pos; // < Size of valid data when pushed to the list
  2899. size_t next_size; // < Next geometrically growing chunk size to allocate
  2900. size_t padding_pos; // < One past the offset of the most recent `ufbxi_buf_padding`
  2901. char data[]; // < Must be aligned to 8 bytes
  2902. };
  2903. ufbx_static_assert(buf_chunk_align, offsetof(ufbxi_buf_chunk, data) % 8 == 0);
  2904. typedef struct {
  2905. ufbxi_allocator *ator;
  2906. // Current chunks for normal and huge allocations.
  2907. // Ordered buffers (`!ufbxi_buf.unordered`) never use `chunks[1]`
  2908. ufbxi_buf_chunk *chunks[2];
  2909. // Inline state for non-huge chunks
  2910. size_t pos; // < Next offset to allocate from
  2911. size_t size; // < Size of the current chunk ie. `chunks[0]->size` (or 0 if `chunks[0] == NULL`)
  2912. size_t num_items; // < Number of individual items pushed to the buffer
  2913. size_t pushed_size; // < Cumulative size of pushed chunks, not tracked across pops
  2914. bool unordered; // < Does not support popping from the buffer
  2915. bool clearable; // < Supports clearing the whole buffer even if `unordered`
  2916. } ufbxi_buf;
  2917. typedef struct {
  2918. ufbxi_buf_chunk *chunk;
  2919. size_t pos;
  2920. size_t num_items;
  2921. } ufbxi_buf_state;
  2922. static ufbxi_noinline void *ufbxi_push_size_new_block(ufbxi_buf *b, size_t size)
  2923. {
  2924. bool huge = size >= b->ator->huge_size;
  2925. // Use the second chunk "list" for huge unordered chunks.
  2926. // The state of these chunks is not tracked by `ufbxi_buf.pos/size`.
  2927. uint32_t list_ix = ((uint32_t)b->unordered & (uint32_t)huge);
  2928. ufbxi_buf_chunk *chunk = b->chunks[list_ix];
  2929. if (chunk) {
  2930. if (list_ix == 0) {
  2931. // Store the final position for the retired chunk and scan free
  2932. // chunks in case we find one the allocation fits in.
  2933. b->pushed_size += b->pos;
  2934. chunk->pushed_pos = b->pos;
  2935. ufbxi_buf_chunk *next = chunk->next;
  2936. while (next != NULL) {
  2937. ufbx_assert(next->magic == UFBXI_BUF_CHUNK_IMP_MAGIC);
  2938. chunk = next;
  2939. ufbx_assert(b->unordered || chunk->pushed_pos == 0);
  2940. chunk->pushed_pos = 0;
  2941. if (size <= chunk->size) {
  2942. b->chunks[0] = chunk;
  2943. b->pos = (uint32_t)size;
  2944. b->size = chunk->size;
  2945. return chunk->data;
  2946. }
  2947. next = chunk->next;
  2948. }
  2949. } else if (b->clearable) {
  2950. // Keep track of the `UFBXI_HUGE_MAX_SCAN` largest chunks and
  2951. // retain them. Overflowing chunks are freed in `ufbxi_buf_clear()`
  2952. size_t align_mask = ufbxi_size_align_mask(size);
  2953. ufbxi_buf_chunk *next = chunk;
  2954. ufbxi_buf_chunk *best_chunk = NULL;
  2955. size_t best_space = SIZE_MAX;
  2956. // Clearable huge chunks are sorted by descending size. Check the first N
  2957. // chunks for reuse and find the place a new block should be inserted if
  2958. // no suitable space is found. Chunk ordering in the tail doesn't matter
  2959. // as those chunks are never reused.
  2960. // Unreachable chunks in the tail are freed in `ufbxi_buf_clear()`.
  2961. for (size_t i = 0; next && i < UFBXI_HUGE_MAX_SCAN; i++) {
  2962. ufbx_assert(next->magic == UFBXI_BUF_CHUNK_IMP_MAGIC);
  2963. if (next->size < size) break;
  2964. chunk = next;
  2965. // Try to reuse chunks using a best-fit strategy.
  2966. size_t pos = ufbxi_align_to_mask(chunk->pushed_pos, align_mask);
  2967. size_t space = chunk->size - pos;
  2968. if (size <= space) {
  2969. if (space < best_space) {
  2970. best_chunk = chunk;
  2971. best_space = space;
  2972. }
  2973. }
  2974. next = chunk->next;
  2975. }
  2976. // Early return if we found a slot.
  2977. if (best_chunk) {
  2978. size_t pos = ufbxi_align_to_mask(best_chunk->pushed_pos, align_mask);
  2979. best_chunk->pushed_pos = pos + size;
  2980. b->pushed_size += size;
  2981. return best_chunk->data + pos;
  2982. }
  2983. }
  2984. }
  2985. // Allocate a new chunk, grow `next_size` geometrically but don't double
  2986. // the current or previous user sizes if they are larger.
  2987. size_t chunk_size, next_size;
  2988. // If `size` is larger than `huge_size` don't grow `next_size` geometrically,
  2989. // but use a dedicated allocation.
  2990. if (huge) {
  2991. next_size = chunk ? chunk->next_size : 4096;
  2992. if (next_size > b->ator->chunk_max) next_size = b->ator->chunk_max;
  2993. chunk_size = size;
  2994. } else {
  2995. next_size = chunk ? chunk->next_size * 2 : 4096;
  2996. if (next_size > b->ator->chunk_max) next_size = b->ator->chunk_max;
  2997. chunk_size = next_size - sizeof(ufbxi_buf_chunk);
  2998. if (chunk_size < size) chunk_size = size;
  2999. }
  3000. // Align chunk sizes to 16 bytes
  3001. chunk_size = ufbxi_align_to_mask(chunk_size, 0xf);
  3002. ufbxi_buf_chunk *new_chunk = (ufbxi_buf_chunk*)ufbxi_alloc_size(b->ator, 1, sizeof(ufbxi_buf_chunk) + chunk_size);
  3003. if (!new_chunk) return NULL;
  3004. new_chunk->prev = chunk;
  3005. new_chunk->size = chunk_size;
  3006. new_chunk->next_size = next_size;
  3007. new_chunk->magic = UFBXI_BUF_CHUNK_IMP_MAGIC;
  3008. new_chunk->padding_pos = 0;
  3009. new_chunk->pushed_pos = 0;
  3010. // Link the chunk to the list and set it as the active one
  3011. if (chunk) {
  3012. ufbxi_buf_chunk *next = chunk->next;
  3013. if (next) next->prev = new_chunk;
  3014. new_chunk->next = next;
  3015. chunk->next = new_chunk;
  3016. new_chunk->root = chunk->root;
  3017. } else {
  3018. new_chunk->next = NULL;
  3019. new_chunk->root = new_chunk;
  3020. }
  3021. if (list_ix == 0) {
  3022. b->chunks[0] = new_chunk;
  3023. b->pos = size;
  3024. b->size = chunk_size;
  3025. } else {
  3026. ufbxi_buf_chunk *root = b->chunks[1];
  3027. b->pushed_size += size;
  3028. if (!root) {
  3029. b->chunks[1] = new_chunk;
  3030. } else if (root->size < chunk_size) {
  3031. // Swap root and self if necessary, we should have bailed out
  3032. // in the search loop in the first iteration so `new_chunk` should
  3033. // directly follow `root`.
  3034. // HACK: This ends up with `chunks[1]` entries having inconsistent
  3035. // `ufbxi_buf_chunk.root` pointers but other code only reads `chunks[1].root`
  3036. // TODO: Move roots out of the chunks?
  3037. ufbx_assert(root->next == new_chunk);
  3038. ufbx_assert(new_chunk->prev == root);
  3039. if (new_chunk->next) new_chunk->next->prev = root;
  3040. root->next = new_chunk->next;
  3041. new_chunk->next = root;
  3042. new_chunk->prev = NULL;
  3043. new_chunk->root = new_chunk;
  3044. b->chunks[1] = new_chunk;
  3045. }
  3046. new_chunk->pushed_pos = size;
  3047. }
  3048. return new_chunk->data;
  3049. }
  3050. static ufbxi_noinline void *ufbxi_push_size(ufbxi_buf *b, size_t size, size_t n)
  3051. {
  3052. // Always succeed with an empty non-NULL buffer for empty allocations
  3053. ufbx_assert(size > 0);
  3054. if (n == 0) return (void*)ufbxi_zero_size_buffer;
  3055. size_t total = size * n;
  3056. if (ufbxi_does_overflow(total, size, n)) return NULL;
  3057. #if defined(UFBX_REGRESSION)
  3058. {
  3059. ufbxi_allocator *ator = b->ator;
  3060. ufbxi_check_return_err_msg(ator->error, ator->num_allocs < ator->max_allocs, NULL, "Allocation limit exceeded");
  3061. ator->num_allocs++;
  3062. }
  3063. #endif
  3064. b->num_items += n;
  3065. // Align to the natural alignment based on the size
  3066. size_t align_mask = ufbxi_size_align_mask(size);
  3067. size_t pos = ufbxi_align_to_mask(b->pos, align_mask);
  3068. if (!b->unordered && pos != b->pos) {
  3069. // Alignment mismatch in an unordered block. Align to 16 bytes to guarantee
  3070. // sufficient alignment for anything afterwards and mark the padding.
  3071. // If we overflow the current block we don't need to care as the block
  3072. // boundaries are not contiguous.
  3073. pos = ufbxi_align_to_mask(b->pos, 0xf);
  3074. if (total < SIZE_MAX - 16 && total + 16 <= b->size - pos) {
  3075. ufbxi_buf_chunk *chunk = b->chunks[0];
  3076. ufbxi_buf_padding *padding = (ufbxi_buf_padding*)(chunk->data + pos);
  3077. padding->original_pos = b->pos;
  3078. padding->prev_padding = chunk->padding_pos;
  3079. chunk->padding_pos = pos + 16 + 1;
  3080. b->pos = pos + 16 + total;
  3081. return (char*)padding + 16;
  3082. } else {
  3083. return ufbxi_push_size_new_block(b, total);
  3084. }
  3085. } else {
  3086. // Try to push to the current block. Allocate a new block
  3087. // if the aligned size doesn't fit.
  3088. if (total <= b->size - pos) {
  3089. b->pos = pos + total;
  3090. return b->chunks[0]->data + pos;
  3091. } else {
  3092. return ufbxi_push_size_new_block(b, total);
  3093. }
  3094. }
  3095. }
  3096. static ufbxi_forceinline void *ufbxi_push_size_fast(ufbxi_buf *b, size_t size, size_t n)
  3097. {
  3098. // Always succeed with an empty non-NULL buffer for empty allocations
  3099. ufbxi_regression_assert(size > 0);
  3100. ufbxi_regression_assert(n > 0);
  3101. size_t total = size * n;
  3102. ufbxi_regression_assert(!ufbxi_does_overflow(total, size, n));
  3103. #if defined(UFBX_REGRESSION)
  3104. {
  3105. ufbxi_allocator *ator = b->ator;
  3106. ufbxi_check_return_err_msg(ator->error, ator->num_allocs < ator->max_allocs, NULL, "Allocation limit exceeded");
  3107. ator->num_allocs++;
  3108. }
  3109. #endif
  3110. b->num_items += n;
  3111. // Homogeneous arrays should always be aligned
  3112. size_t pos = b->pos;
  3113. ufbxi_regression_assert((pos & ufbxi_size_align_mask(size)) == 0);
  3114. // Try to push to the current block. Allocate a new block
  3115. // if the aligned size doesn't fit.
  3116. if (total <= b->size - pos) {
  3117. b->pos = pos + total;
  3118. return b->chunks[0]->data + pos;
  3119. } else {
  3120. return ufbxi_push_size_new_block(b, total);
  3121. }
  3122. }
  3123. static ufbxi_noinline void *ufbxi_push_size_zero(ufbxi_buf *b, size_t size, size_t n)
  3124. {
  3125. void *ptr = ufbxi_push_size(b, size, n);
  3126. if (ptr) memset(ptr, 0, size * n);
  3127. return ptr;
  3128. }
  3129. ufbxi_nodiscard static ufbxi_noinline void *ufbxi_push_size_copy(ufbxi_buf *b, size_t size, size_t n, const void *data)
  3130. {
  3131. // Always succeed with an empty non-NULL buffer for empty allocations, even if `data == NULL`
  3132. ufbx_assert(size > 0);
  3133. if (n == 0) return (void*)ufbxi_zero_size_buffer;
  3134. ufbx_assert(data);
  3135. void *ptr = ufbxi_push_size(b, size, n);
  3136. if (ptr) memcpy(ptr, data, size * n);
  3137. return ptr;
  3138. }
  3139. ufbxi_nodiscard static ufbxi_forceinline void *ufbxi_push_size_copy_fast(ufbxi_buf *b, size_t size, size_t n, const void *data)
  3140. {
  3141. // Always succeed with an empty non-NULL buffer for empty allocations, even if `data == NULL`
  3142. ufbx_assert(size > 0);
  3143. if (n == 0) return (void*)ufbxi_zero_size_buffer;
  3144. ufbx_assert(data);
  3145. void *ptr = ufbxi_push_size_fast(b, size, n);
  3146. if (ptr) memcpy(ptr, data, size * n);
  3147. return ptr;
  3148. }
  3149. static ufbxi_noinline void ufbxi_buf_free_unused(ufbxi_buf *b)
  3150. {
  3151. ufbx_assert(!b->unordered);
  3152. ufbxi_buf_chunk *chunk = b->chunks[0];
  3153. if (!chunk) return;
  3154. ufbxi_buf_chunk *next = chunk->next;
  3155. while (next) {
  3156. ufbxi_buf_chunk *to_free = next;
  3157. next = next->next;
  3158. ufbx_assert(to_free->magic == UFBXI_BUF_CHUNK_IMP_MAGIC);
  3159. to_free->magic = 0;
  3160. ufbxi_free_size(b->ator, 1, to_free, sizeof(ufbxi_buf_chunk) + to_free->size);
  3161. }
  3162. chunk->next = NULL;
  3163. while (b->pos == 0 && chunk) {
  3164. ufbxi_buf_chunk *prev = chunk->prev;
  3165. ufbx_assert(chunk->magic == UFBXI_BUF_CHUNK_IMP_MAGIC);
  3166. chunk->magic = 0;
  3167. ufbxi_free_size(b->ator, 1, chunk, sizeof(ufbxi_buf_chunk) + chunk->size);
  3168. chunk = prev;
  3169. b->chunks[0] = prev;
  3170. if (prev) {
  3171. prev->next = NULL;
  3172. b->pos = prev->pushed_pos;
  3173. b->size = prev->size;
  3174. } else {
  3175. b->pos = 0;
  3176. b->size = 0;
  3177. }
  3178. }
  3179. }
  3180. static ufbxi_noinline void ufbxi_pop_size(ufbxi_buf *b, size_t size, size_t n, void *dst, bool peek)
  3181. {
  3182. ufbx_assert(!b->unordered);
  3183. ufbx_assert(size > 0);
  3184. ufbx_assert(b->num_items >= n);
  3185. if (!peek) b->num_items -= n;
  3186. char *ptr = (char*)dst;
  3187. size_t bytes_left = size * n;
  3188. // We've already pushed this, it better not overflow
  3189. ufbx_assert(!ufbxi_does_overflow(bytes_left, size, n));
  3190. if (ptr) {
  3191. ptr += bytes_left;
  3192. size_t pos = b->pos;
  3193. ufbxi_buf_chunk *chunk = b->chunks[0];
  3194. for (;;) {
  3195. if (bytes_left <= pos) {
  3196. // Rest of the data is in this single chunk
  3197. pos -= bytes_left;
  3198. if (!peek) b->pos = pos;
  3199. ptr -= bytes_left;
  3200. if (bytes_left > 0) {
  3201. memcpy(ptr, chunk->data + pos, bytes_left);
  3202. }
  3203. break;
  3204. } else {
  3205. // Pop the whole chunk
  3206. ptr -= pos;
  3207. bytes_left -= pos;
  3208. memcpy(ptr, chunk->data, pos);
  3209. if (!peek) {
  3210. chunk->pushed_pos = 0;
  3211. chunk = chunk->prev;
  3212. b->chunks[0] = chunk;
  3213. b->size = chunk->size;
  3214. } else {
  3215. chunk = chunk->prev;
  3216. }
  3217. pos = chunk->pushed_pos;
  3218. }
  3219. }
  3220. } else {
  3221. size_t pos = b->pos;
  3222. ufbxi_buf_chunk *chunk = b->chunks[0];
  3223. for (;;) {
  3224. if (bytes_left <= pos) {
  3225. // Rest of the data is in this single chunk
  3226. pos -= bytes_left;
  3227. if (!peek) b->pos = pos;
  3228. break;
  3229. } else {
  3230. // Pop the whole chunk
  3231. bytes_left -= pos;
  3232. if (!peek) {
  3233. chunk->pushed_pos = 0;
  3234. chunk = chunk->prev;
  3235. b->chunks[0] = chunk;
  3236. b->size = chunk->size;
  3237. } else {
  3238. chunk = chunk->prev;
  3239. }
  3240. pos = chunk->pushed_pos;
  3241. }
  3242. }
  3243. }
  3244. if (!peek) {
  3245. // Check if we need to rewind past some alignment padding
  3246. ufbxi_buf_chunk *chunk = b->chunks[0];
  3247. if (chunk) {
  3248. size_t pos = b->pos, padding_pos = chunk->padding_pos;
  3249. if (pos < padding_pos) {
  3250. ufbx_assert(pos + 1 == padding_pos);
  3251. ufbxi_buf_padding *padding = (ufbxi_buf_padding*)(chunk->data + padding_pos - 1 - 16);
  3252. b->pos = padding->original_pos;
  3253. chunk->padding_pos = padding->prev_padding;
  3254. }
  3255. }
  3256. // Immediately free popped items if all the allocations are huge
  3257. // as it means we want to have dedicated allocations for each push.
  3258. if (b->ator->huge_size <= 1) {
  3259. ufbxi_buf_free_unused(b);
  3260. }
  3261. }
  3262. }
  3263. static ufbxi_noinline void *ufbxi_push_pop_size(ufbxi_buf *dst, ufbxi_buf *src, size_t size, size_t n)
  3264. {
  3265. void *data = ufbxi_push_size(dst, size, n);
  3266. if (!data) return NULL;
  3267. ufbxi_pop_size(src, size, n, data, false);
  3268. return data;
  3269. }
  3270. static ufbxi_noinline void *ufbxi_push_peek_size(ufbxi_buf *dst, ufbxi_buf *src, size_t size, size_t n)
  3271. {
  3272. void *data = ufbxi_push_size(dst, size, n);
  3273. if (!data) return NULL;
  3274. ufbxi_pop_size(src, size, n, data, true);
  3275. return data;
  3276. }
  3277. static ufbxi_noinline void ufbxi_buf_free(ufbxi_buf *buf)
  3278. {
  3279. ufbxi_nounroll for (size_t i = 0; i < 2; i++) {
  3280. ufbxi_buf_chunk *chunk = buf->chunks[i];
  3281. if (chunk) {
  3282. chunk = chunk->root;
  3283. while (chunk) {
  3284. ufbxi_buf_chunk *next = chunk->next;
  3285. ufbx_assert(chunk->magic == UFBXI_BUF_CHUNK_IMP_MAGIC);
  3286. chunk->magic = 0;
  3287. ufbxi_free_size(buf->ator, 1, chunk, sizeof(ufbxi_buf_chunk) + chunk->size);
  3288. chunk = next;
  3289. }
  3290. }
  3291. buf->chunks[i] = NULL;
  3292. }
  3293. buf->pos = 0;
  3294. buf->size = 0;
  3295. buf->num_items = 0;
  3296. }
  3297. static ufbxi_noinline void ufbxi_buf_clear(ufbxi_buf *buf)
  3298. {
  3299. // Only unordered or clearable buffers can be cleared
  3300. ufbx_assert(!buf->unordered || buf->clearable);
  3301. // Free the memory if using ASAN
  3302. if (buf->ator->huge_size <= 1) {
  3303. ufbxi_buf_free(buf);
  3304. return;
  3305. }
  3306. // Reset the non-huge chunks as `chunk->next` is always free.
  3307. ufbxi_buf_chunk *chunk = buf->chunks[0];
  3308. if (chunk) {
  3309. ufbxi_buf_chunk *root = chunk->root;
  3310. buf->chunks[0] = root;
  3311. buf->pos = 0;
  3312. buf->size = root->size;
  3313. }
  3314. buf->num_items = 0;
  3315. buf->pushed_size = 0;
  3316. // Huge chunks are always sorted by descending size and
  3317. // `chunks[1]` points to the largest one.
  3318. ufbxi_buf_chunk *huge = buf->chunks[1];
  3319. if (huge) {
  3320. // Reset the first N ones that are tracked.
  3321. for (size_t i = 0; huge && i < UFBXI_HUGE_MAX_SCAN; i++) {
  3322. huge->pushed_pos = 0;
  3323. huge = huge->next;
  3324. }
  3325. // Got unreachable tail that should be freed: Unlink from the last
  3326. // tracked chunk and free the rest.
  3327. if (huge) {
  3328. huge->prev->next = NULL;
  3329. while (huge) {
  3330. ufbxi_buf_chunk *next = huge->next;
  3331. ufbx_assert(huge->magic == UFBXI_BUF_CHUNK_IMP_MAGIC);
  3332. huge->magic = 0;
  3333. ufbxi_free_size(buf->ator, 1, huge, sizeof(ufbxi_buf_chunk) + huge->size);
  3334. huge = next;
  3335. }
  3336. }
  3337. }
  3338. }
  3339. #define ufbxi_push(b, type, n) ufbxi_maybe_null((type*)ufbxi_push_size((b), sizeof(type), (n)))
  3340. #define ufbxi_push_zero(b, type, n) ufbxi_maybe_null((type*)ufbxi_push_size_zero((b), sizeof(type), (n)))
  3341. #define ufbxi_push_copy(b, type, n, data) ufbxi_maybe_null((type*)ufbxi_push_size_copy((b), sizeof(type), (n), (data)))
  3342. #define ufbxi_push_copy_fast(b, type, n, data) ufbxi_maybe_null((type*)ufbxi_push_size_copy_fast((b), sizeof(type), (n), (data)))
  3343. #define ufbxi_push_fast(b, type, n) ufbxi_maybe_null((type*)ufbxi_push_size_fast((b), sizeof(type), (n)))
  3344. #define ufbxi_pop(b, type, n, dst) ufbxi_pop_size((b), sizeof(type), (n), (dst), false)
  3345. #define ufbxi_peek(b, type, n, dst) ufbxi_pop_size((b), sizeof(type), (n), (dst), true)
  3346. #define ufbxi_push_pop(dst, src, type, n) ufbxi_maybe_null((type*)ufbxi_push_pop_size((dst), (src), sizeof(type), (n)))
  3347. #define ufbxi_push_peek(dst, src, type, n) ufbxi_maybe_null((type*)ufbxi_push_peek_size((dst), (src), sizeof(type), (n)))
  3348. // -- Hash map
  3349. //
  3350. // The actual element comparison is left to the user of `ufbxi_map`, see usage below.
  3351. //
  3352. // NOTES:
  3353. // ufbxi_map_insert() does not support duplicate values, use find first if duplicates are possible!
  3354. // Inserting duplicate elements fails with an assertion if `UFBX_REGRESSION` is enabled.
  3355. typedef struct ufbxi_aa_node ufbxi_aa_node;
  3356. typedef int ufbxi_cmp_fn(void *user, const void *a, const void *b);
  3357. struct ufbxi_aa_node {
  3358. ufbxi_aa_node *left, *right;
  3359. uint32_t level;
  3360. uint32_t index;
  3361. };
  3362. typedef struct {
  3363. ufbxi_allocator *ator;
  3364. size_t data_size;
  3365. void *items;
  3366. uint64_t *entries;
  3367. uint32_t mask;
  3368. uint32_t capacity;
  3369. uint32_t size;
  3370. ufbxi_cmp_fn *cmp_fn;
  3371. void *cmp_user;
  3372. ufbxi_buf aa_buf;
  3373. ufbxi_aa_node *aa_root;
  3374. } ufbxi_map;
  3375. static ufbxi_noinline void ufbxi_map_init(ufbxi_map *map, ufbxi_allocator *ator, ufbxi_cmp_fn *cmp_fn, void *cmp_user)
  3376. {
  3377. map->ator = ator;
  3378. #if defined(UFBX_REGRESSION)
  3379. // HACK: Maps contain pointers that are not stable between runs, in regression
  3380. // mode this causes instability in allocation patterns due to different AA trees
  3381. // being built, which is a problem in fuzz checks that need to have deterministic
  3382. // allocation counts. We can work around this using a local allocator that doesn't
  3383. // count the allocations.
  3384. {
  3385. ufbxi_allocator *regression_ator = (ufbxi_allocator*)malloc(sizeof(ufbxi_allocator));
  3386. ufbx_assert(regression_ator);
  3387. memset(regression_ator, 0, sizeof(ufbxi_allocator));
  3388. regression_ator->name = "regression";
  3389. regression_ator->error = ator->error;
  3390. regression_ator->huge_size = ator->huge_size;
  3391. regression_ator->max_size = SIZE_MAX;
  3392. regression_ator->max_allocs = SIZE_MAX;
  3393. regression_ator->chunk_max = 0x1000000;
  3394. map->aa_buf.ator = regression_ator;
  3395. }
  3396. #else
  3397. map->aa_buf.ator = ator;
  3398. #endif
  3399. map->cmp_fn = cmp_fn;
  3400. map->cmp_user = cmp_user;
  3401. }
  3402. static ufbxi_noinline void ufbxi_map_free(ufbxi_map *map)
  3403. {
  3404. #if defined(UFBX_REGRESSION)
  3405. ufbxi_allocator *regression_ator = map->aa_buf.ator;
  3406. #endif
  3407. ufbxi_buf_free(&map->aa_buf);
  3408. ufbxi_free(map->ator, char, map->entries, map->data_size);
  3409. map->entries = NULL;
  3410. map->items = NULL;
  3411. map->aa_root = NULL;
  3412. map->mask = map->capacity = map->size = 0;
  3413. #if defined(UFBX_REGRESSION)
  3414. if (regression_ator) {
  3415. ufbxi_free_ator(regression_ator);
  3416. free(regression_ator);
  3417. }
  3418. #endif
  3419. }
  3420. // Recursion limit: log2(2^64 / sizeof(ufbxi_aa_node))
  3421. static ufbxi_noinline ufbxi_aa_node *ufbxi_aa_tree_insert(ufbxi_map *map, ufbxi_aa_node *node, const void *value, uint32_t index, size_t item_size)
  3422. ufbxi_recursive_function(ufbxi_aa_node *, ufbxi_aa_tree_insert, (map, node, value, index, item_size), 59,
  3423. (ufbxi_map *map, ufbxi_aa_node *node, const void *value, uint32_t index, size_t item_size))
  3424. {
  3425. if (!node) {
  3426. ufbxi_aa_node *new_node = ufbxi_push(&map->aa_buf, ufbxi_aa_node, 1);
  3427. if (!new_node) return NULL;
  3428. new_node->left = NULL;
  3429. new_node->right = NULL;
  3430. new_node->level = 1;
  3431. new_node->index = index;
  3432. return new_node;
  3433. }
  3434. void *entry = (char*)map->items + node->index * item_size;
  3435. int cmp = map->cmp_fn(map->cmp_user, value, entry);
  3436. if (cmp < 0) {
  3437. node->left = ufbxi_aa_tree_insert(map, node->left, value, index, item_size);
  3438. } else if (cmp >= 0) {
  3439. node->right = ufbxi_aa_tree_insert(map, node->right, value, index, item_size);
  3440. }
  3441. if (node->left && node->left->level == node->level) {
  3442. ufbxi_aa_node *left = node->left;
  3443. node->left = left->right;
  3444. left->right = node;
  3445. node = left;
  3446. }
  3447. if (node->right && node->right->right && node->right->right->level == node->level) {
  3448. ufbxi_aa_node *right = node->right;
  3449. node->right = right->left;
  3450. right->left = node;
  3451. right->level += 1;
  3452. node = right;
  3453. }
  3454. return node;
  3455. }
  3456. static ufbxi_noinline void *ufbxi_aa_tree_find(ufbxi_map *map, const void *value, size_t item_size)
  3457. {
  3458. ufbxi_aa_node *node = map->aa_root;
  3459. while (node) {
  3460. void *entry = (char*)map->items + node->index * item_size;
  3461. int cmp = map->cmp_fn(map->cmp_user, value, entry);
  3462. if (cmp < 0) {
  3463. node = node->left;
  3464. } else if (cmp > 0) {
  3465. node = node->right;
  3466. } else {
  3467. return entry;
  3468. }
  3469. }
  3470. return NULL;
  3471. }
  3472. static ufbxi_noinline bool ufbxi_map_grow_size_imp(ufbxi_map *map, size_t item_size, size_t min_size)
  3473. {
  3474. ufbx_assert(min_size > 0);
  3475. const double load_factor = 0.7;
  3476. // Find the lowest power of two size that fits `min_size` within `load_factor`
  3477. size_t num_entries = map->mask + 1;
  3478. size_t new_size = (size_t)((double)num_entries * load_factor);
  3479. if (min_size < map->capacity + 1) min_size = map->capacity + 1;
  3480. while (new_size < min_size) {
  3481. num_entries *= 2;
  3482. new_size = (size_t)((double)num_entries * load_factor);
  3483. }
  3484. // Check for overflow
  3485. ufbxi_check_return_err(map->ator->error, SIZE_MAX / num_entries > sizeof(uint64_t), false);
  3486. size_t alloc_size = num_entries * sizeof(uint64_t);
  3487. // Allocate a combined entry/item memory block
  3488. ufbxi_check_return_err(map->ator->error, (SIZE_MAX - alloc_size) / new_size > item_size, false);
  3489. size_t data_size = alloc_size + new_size * item_size;
  3490. char *data = ufbxi_alloc(map->ator, char, data_size);
  3491. ufbxi_check_return_err(map->ator->error, data, false);
  3492. // Copy the previous user items over
  3493. uint64_t *old_entries = map->entries;
  3494. uint64_t *new_entries = (uint64_t*)data;
  3495. void *new_items = data + alloc_size;
  3496. if (map->size > 0) {
  3497. memcpy(new_items, map->items, item_size * map->size);
  3498. }
  3499. // Re-hash the entries
  3500. uint32_t old_mask = map->mask;
  3501. uint32_t new_mask = (uint32_t)(num_entries) - 1;
  3502. memset(new_entries, 0, sizeof(uint64_t) * num_entries);
  3503. if (old_mask) {
  3504. for (uint32_t i = 0; i <= old_mask; i++) {
  3505. uint64_t entry, new_entry = old_entries[i];
  3506. if (!new_entry) continue;
  3507. // Reconstruct the hash of the old entry at `i`
  3508. uint32_t old_scan = (uint32_t)(new_entry & old_mask) - 1;
  3509. uint32_t hash = ((uint32_t)new_entry & ~old_mask) | ((i - old_scan) & old_mask);
  3510. uint32_t slot = hash & new_mask;
  3511. new_entry &= ~(uint64_t)new_mask;
  3512. // Scan forward until we find an empty slot, potentially swapping
  3513. // `new_element` if it has a shorter scan distance (Robin Hood).
  3514. uint32_t scan = 1;
  3515. while ((entry = new_entries[slot]) != 0) {
  3516. uint32_t entry_scan = (uint32_t)(entry & new_mask);
  3517. if (entry_scan < scan) {
  3518. new_entries[slot] = new_entry + scan;
  3519. new_entry = (entry & ~(uint64_t)new_mask);
  3520. scan = entry_scan;
  3521. }
  3522. scan += 1;
  3523. slot = (slot + 1) & new_mask;
  3524. }
  3525. new_entries[slot] = new_entry + scan;
  3526. }
  3527. }
  3528. // And finally free the previous allocation
  3529. ufbxi_free(map->ator, char, (char*)old_entries, map->data_size);
  3530. map->items = new_items;
  3531. map->data_size = data_size;
  3532. map->entries = new_entries;
  3533. map->mask = new_mask;
  3534. map->capacity = (uint32_t)new_size;
  3535. return true;
  3536. }
  3537. static ufbxi_forceinline bool ufbxi_map_grow_size(ufbxi_map *map, size_t size, size_t min_size)
  3538. {
  3539. #if defined(UFBX_REGRESSION)
  3540. {
  3541. ufbxi_allocator *ator = map->ator;
  3542. ufbxi_check_return_err_msg(ator->error, ator->num_allocs < ator->max_allocs, false, "Allocation limit exceeded");
  3543. ator->num_allocs++;
  3544. }
  3545. #endif
  3546. if (map->size < map->capacity && map->capacity >= min_size) return true;
  3547. return ufbxi_map_grow_size_imp(map, size, min_size);
  3548. }
  3549. static ufbxi_noinline void *ufbxi_map_find_size(ufbxi_map *map, size_t size, uint32_t hash, const void *value)
  3550. {
  3551. uint64_t *entries = map->entries;
  3552. uint32_t mask = map->mask, scan = 0;
  3553. uint32_t ref = hash & ~mask;
  3554. if (!mask || scan == UINT32_MAX) return 0;
  3555. // Scan entries until we find an exact match of the hash or until we hit
  3556. // an element that has lower scan distance than our search (Robin Hood).
  3557. // The encoding guarantees that zero slots also terminate with the same test.
  3558. for (;;) {
  3559. uint64_t entry = entries[(hash + scan) & mask];
  3560. scan += 1;
  3561. if ((uint32_t)entry == ref + scan) {
  3562. uint32_t index = (uint32_t)(entry >> 32u);
  3563. void *data = (char*)map->items + size * index;
  3564. int cmp = map->cmp_fn(map->cmp_user, value, data);
  3565. if (cmp == 0) return data;
  3566. } else if ((entry & mask) < scan) {
  3567. if (map->aa_root) {
  3568. return ufbxi_aa_tree_find(map, value, size);
  3569. } else {
  3570. return NULL;
  3571. }
  3572. }
  3573. }
  3574. }
  3575. static ufbxi_noinline void *ufbxi_map_insert_size(ufbxi_map *map, size_t size, uint32_t hash, const void *value)
  3576. {
  3577. if (!ufbxi_map_grow_size(map, size, 64)) return NULL;
  3578. ufbxi_regression_assert(ufbxi_map_find_size(map, size, hash, value) == NULL);
  3579. uint32_t index = map->size++;
  3580. uint64_t *entries = map->entries;
  3581. uint32_t mask = map->mask;
  3582. // Scan forward until we find an empty slot, potentially swapping
  3583. // `new_element` if it has a shorter scan distance (Robin Hood).
  3584. uint32_t slot = hash & mask;
  3585. uint64_t entry, new_entry = (uint64_t)index << 32u | (hash & ~mask);
  3586. uint32_t scan = 1;
  3587. while ((entry = entries[slot]) != 0) {
  3588. uint32_t entry_scan = (uint32_t)(entry & mask);
  3589. if (entry_scan < scan) {
  3590. entries[slot] = new_entry + scan;
  3591. new_entry = (entry & ~(uint64_t)mask);
  3592. scan = entry_scan;
  3593. }
  3594. scan += 1;
  3595. slot = (slot + 1) & mask;
  3596. if (scan > UFBXI_MAP_MAX_SCAN) {
  3597. uint32_t new_index = (uint32_t)(new_entry >> 32u);
  3598. const void *new_value = new_index == index ? value : (const void*)((char*)map->items + size * new_index);
  3599. map->aa_root = ufbxi_aa_tree_insert(map, map->aa_root, new_value, new_index, size);
  3600. return (char*)map->items + size * index;
  3601. }
  3602. }
  3603. entries[slot] = new_entry + scan;
  3604. return (char*)map->items + size * index;
  3605. }
  3606. #define ufbxi_map_grow(map, type, min_size) ufbxi_map_grow_size((map), sizeof(type), (min_size))
  3607. #define ufbxi_map_find(map, type, hash, value) ufbxi_maybe_null((type*)ufbxi_map_find_size((map), sizeof(type), (hash), (value)))
  3608. #define ufbxi_map_insert(map, type, hash, value) ufbxi_maybe_null((type*)ufbxi_map_insert_size((map), sizeof(type), (hash), (value)))
  3609. static int ufbxi_map_cmp_uint64(void *user, const void *va, const void *vb)
  3610. {
  3611. (void)user;
  3612. uint64_t a = *(const uint64_t*)va, b = *(const uint64_t*)vb;
  3613. if (a < b) return -1;
  3614. if (a > b) return +1;
  3615. return 0;
  3616. }
  3617. static int ufbxi_map_cmp_const_char_ptr(void *user, const void *va, const void *vb)
  3618. {
  3619. (void)user;
  3620. const char *a = *(const char **)va, *b = *(const char **)vb;
  3621. if (a < b) return -1;
  3622. if (a > b) return +1;
  3623. return 0;
  3624. }
  3625. static int ufbxi_map_cmp_uintptr(void *user, const void *va, const void *vb)
  3626. {
  3627. (void)user;
  3628. uintptr_t a = *(const uintptr_t*)va, b = *(const uintptr_t*)vb;
  3629. if (a < b) return -1;
  3630. if (a > b) return +1;
  3631. return 0;
  3632. }
  3633. // -- Hash functions
  3634. static ufbxi_noinline uint32_t ufbxi_hash_string(const char *str, size_t length)
  3635. {
  3636. uint32_t hash = (uint32_t)length;
  3637. uint32_t seed = UINT32_C(0x9e3779b9);
  3638. if (length >= 4) {
  3639. do {
  3640. uint32_t word = ufbxi_read_u32(str);
  3641. hash = ((hash << 5u | hash >> 27u) ^ word) * seed;
  3642. str += 4;
  3643. length -= 4;
  3644. } while (length >= 4);
  3645. uint32_t word = ufbxi_read_u32(str + length - 4);
  3646. hash = ((hash << 5u | hash >> 27u) ^ word) * seed;
  3647. } else {
  3648. uint32_t word = 0;
  3649. if (length >= 1) word |= (uint32_t)(uint8_t)str[0] << 0;
  3650. if (length >= 2) word |= (uint32_t)(uint8_t)str[1] << 8;
  3651. if (length >= 3) word |= (uint32_t)(uint8_t)str[2] << 16;
  3652. hash = ((hash << 5u | hash >> 27u) ^ word) * seed;
  3653. }
  3654. hash ^= hash >> 16;
  3655. hash *= UINT32_C(0x7feb352d);
  3656. hash ^= hash >> 15;
  3657. return hash;
  3658. }
  3659. // NOTE: _Must_ match `ufbxi_hash_string()`
  3660. static ufbxi_noinline uint32_t ufbxi_hash_string_check_ascii(const char *str, size_t length, bool *p_non_ascii)
  3661. {
  3662. uint32_t ascii_mask = 0;
  3663. uint32_t zero_mask = 0;
  3664. ufbx_assert(length > 0);
  3665. uint32_t hash = (uint32_t)length;
  3666. uint32_t seed = UINT32_C(0x9e3779b9);
  3667. if (length >= 4) {
  3668. do {
  3669. uint32_t word = ufbxi_read_u32(str);
  3670. ascii_mask |= word;
  3671. zero_mask |= UINT32_C(0x80808080) - word;
  3672. hash = ((hash << 5u | hash >> 27u) ^ word) * seed;
  3673. str += 4;
  3674. length -= 4;
  3675. } while (length >= 4);
  3676. uint32_t word = ufbxi_read_u32(str + length - 4);
  3677. ascii_mask |= word;
  3678. zero_mask |= UINT32_C(0x80808080) - word;
  3679. hash = ((hash << 5u | hash >> 27u) ^ word) * seed;
  3680. } else {
  3681. uint32_t word = 0;
  3682. if (length >= 1) word |= (uint32_t)(uint8_t)str[0] << 0;
  3683. if (length >= 2) word |= (uint32_t)(uint8_t)str[1] << 8;
  3684. if (length >= 3) word |= (uint32_t)(uint8_t)str[2] << 16;
  3685. ascii_mask |= word;
  3686. zero_mask |= (UINT32_C(0x80808080) >> ((4u - length) * 8u)) - word;
  3687. hash = ((hash << 5u | hash >> 27u) ^ word) * seed;
  3688. }
  3689. // If any character has high bit set or is zero we're not ASCII
  3690. if (((ascii_mask | zero_mask) & 0x80808080u) != 0) {
  3691. *p_non_ascii = true;
  3692. }
  3693. hash ^= hash >> 16;
  3694. hash *= UINT32_C(0x7feb352d);
  3695. hash ^= hash >> 15;
  3696. return hash;
  3697. }
  3698. static ufbxi_forceinline uint32_t ufbxi_hash32(uint32_t x)
  3699. {
  3700. x ^= x >> 16;
  3701. x *= UINT32_C(0x7feb352d);
  3702. x ^= x >> 15;
  3703. x *= UINT32_C(0x846ca68b);
  3704. x ^= x >> 16;
  3705. return x;
  3706. }
  3707. static ufbxi_forceinline uint32_t ufbxi_hash64(uint64_t x)
  3708. {
  3709. x ^= x >> 32;
  3710. x *= UINT64_C(0xd6e8feb86659fd93);
  3711. x ^= x >> 32;
  3712. x *= UINT64_C(0xd6e8feb86659fd93);
  3713. x ^= x >> 32;
  3714. return (uint32_t)x;
  3715. }
  3716. static ufbxi_forceinline uint32_t ufbxi_hash_uptr(uintptr_t ptr)
  3717. {
  3718. return sizeof(ptr) == 8 ? ufbxi_hash64((uint64_t)ptr) : ufbxi_hash32((uint32_t)ptr);
  3719. }
  3720. #define ufbxi_hash_ptr(ptr) ufbxi_hash_uptr((uintptr_t)(ptr))
  3721. // -- Warnings
  3722. typedef struct {
  3723. ufbx_error *error;
  3724. ufbxi_buf *result;
  3725. ufbxi_buf tmp_stack;
  3726. uint32_t deferred_element_id_plus_one;
  3727. // Separate lists for specific and non-specific warnings
  3728. ufbx_warning *prev_warnings[UFBX_WARNING_TYPE_COUNT][2];
  3729. } ufbxi_warnings;
  3730. ufbxi_nodiscard static ufbxi_noinline int ufbxi_vwarnf_imp(ufbxi_warnings *ws, ufbx_warning_type type, uint32_t element_id, const char *fmt, va_list args)
  3731. {
  3732. if (!ws) return 1;
  3733. // HACK(warning-element): Encode potential deferred element ID into `ufbx_warning.element_id`,
  3734. // `ws->element_id_index_plus_one` contains index to `uc->tmp_element_id`.
  3735. // Tag deferred indices with the high bit.
  3736. if (element_id == ~0u && ws->deferred_element_id_plus_one > 0) {
  3737. element_id = (ws->deferred_element_id_plus_one - 1) | 0x80000000u;
  3738. }
  3739. uint32_t has_element_id = element_id != ~0u;
  3740. if (type >= UFBX_WARNING_TYPE_FIRST_DEDUPLICATED) {
  3741. ufbx_warning *prev = ws->prev_warnings[type][has_element_id];
  3742. if (prev && prev->element_id == element_id) {
  3743. prev->count++;
  3744. return 1;
  3745. }
  3746. }
  3747. char desc[256];
  3748. size_t desc_len = (size_t)ufbxi_vsnprintf(desc, sizeof(desc), fmt, args);
  3749. ufbxi_clean_string_utf8(desc, desc_len);
  3750. char *desc_copy = ufbxi_push_copy(ws->result, char, desc_len + 1, desc);
  3751. ufbxi_check_err(ws->error, desc_copy);
  3752. ufbx_warning *warning = ufbxi_push(&ws->tmp_stack, ufbx_warning, 1);
  3753. ufbxi_check_err(ws->error, warning);
  3754. warning->type = type;
  3755. warning->description.data = desc_copy;
  3756. warning->description.length = desc_len;
  3757. warning->element_id = element_id;
  3758. warning->count = 1;
  3759. ws->prev_warnings[type][has_element_id] = warning;
  3760. return 1;
  3761. }
  3762. ufbxi_nodiscard static ufbxi_noinline int ufbxi_warnf_imp(ufbxi_warnings *ws, ufbx_warning_type type, uint32_t element_id, const char *fmt, ...)
  3763. {
  3764. // NOTE: `ws` may be `NULL` here, handled by `ufbxi_vwarnf()`
  3765. va_list args; // ufbxi_uninit
  3766. va_start(args, fmt);
  3767. int ok = ufbxi_vwarnf_imp(ws, type, element_id, fmt, args);
  3768. va_end(args);
  3769. return ok;
  3770. }
  3771. ufbxi_nodiscard static ufbxi_noinline int ufbxi_pop_warnings(ufbxi_warnings *ws, ufbx_warning_list *warnings, bool *p_has_warning)
  3772. {
  3773. warnings->count = ws->tmp_stack.num_items;
  3774. warnings->data = ufbxi_push_pop(ws->result, &ws->tmp_stack, ufbx_warning, warnings->count);
  3775. ufbxi_check_err(ws->error, warnings->data);
  3776. ufbxi_for_list(ufbx_warning, warning, *warnings) {
  3777. p_has_warning[warning->type] = true;
  3778. }
  3779. return 1;
  3780. }
  3781. // -- String pool
  3782. // All strings found in FBX files are interned for deduplication and fast
  3783. // comparison. Our fixed internal strings (`ufbxi_String`) are considered the
  3784. // canonical pointers for said strings so we can compare them by address.
  3785. typedef struct {
  3786. ufbx_error *error;
  3787. ufbxi_buf buf; // < Buffer for the actual string data
  3788. ufbxi_map map; // < Map of `ufbxi_string`
  3789. size_t initial_size; // < Number of initial entries
  3790. char *temp_str; // < Temporary string buffer of `temp_cap`
  3791. size_t temp_cap; // < Capacity of the temporary buffer
  3792. ufbx_unicode_error_handling error_handling;
  3793. ufbxi_warnings *warnings;
  3794. } ufbxi_string_pool;
  3795. typedef struct {
  3796. const char *raw_data; // < UTF-8 data follows at `raw_length+1` if `utf8_length > 0`
  3797. uint32_t raw_length; // < Length of the non-sanitized original string
  3798. uint32_t utf8_length; // < Length of sanitized UTF-8 string (or zero)
  3799. } ufbxi_sanitized_string;
  3800. static ufbxi_forceinline bool ufbxi_str_equal(ufbx_string a, ufbx_string b)
  3801. {
  3802. return a.length == b.length && !memcmp(a.data, b.data, a.length);
  3803. }
  3804. static ufbxi_forceinline bool ufbxi_str_less(ufbx_string a, ufbx_string b)
  3805. {
  3806. size_t len = ufbxi_min_sz(a.length, b.length);
  3807. int cmp = memcmp(a.data, b.data, len);
  3808. if (cmp != 0) return cmp < 0;
  3809. return a.length < b.length;
  3810. }
  3811. static ufbxi_forceinline int ufbxi_str_cmp(ufbx_string a, ufbx_string b)
  3812. {
  3813. size_t len = ufbxi_min_sz(a.length, b.length);
  3814. int cmp = memcmp(a.data, b.data, len);
  3815. if (cmp != 0) return cmp;
  3816. if (a.length != b.length) return a.length < b.length ? -1 : 1;
  3817. return 0;
  3818. }
  3819. static ufbxi_forceinline ufbx_string ufbxi_str_c(const char *str)
  3820. {
  3821. ufbx_string s = { str, strlen(str) };
  3822. return s;
  3823. }
  3824. static ufbxi_noinline uint32_t ufbxi_get_concat_key(const ufbx_string *parts, size_t num_parts)
  3825. {
  3826. uint32_t key = 0, shift = 32;
  3827. ufbxi_for(const ufbx_string, part, parts, num_parts) {
  3828. size_t length = part->length != SIZE_MAX ? part->length : strlen(part->data);
  3829. for (size_t i = 0; i < length; i++) {
  3830. shift -= 8;
  3831. key |= (uint32_t)(uint8_t)part->data[i] << shift;
  3832. if (shift == 0) return key;
  3833. }
  3834. }
  3835. return key;
  3836. }
  3837. static ufbxi_noinline int ufbxi_concat_str_cmp(const ufbx_string *ref, const ufbx_string *parts, size_t num_parts)
  3838. {
  3839. const char *ptr = ref->data, *end = ptr + ref->length;
  3840. ufbxi_for(const ufbx_string, part, parts, num_parts) {
  3841. size_t length = part->length != SIZE_MAX ? part->length : strlen(part->data);
  3842. size_t to_cmp = ufbxi_min_sz(ufbxi_to_size(end - ptr), length);
  3843. int cmp = to_cmp > 0 ? memcmp(ptr, part->data, to_cmp) : 0;
  3844. if (cmp != 0) return cmp;
  3845. if (to_cmp != length) return -1;
  3846. ptr += length;
  3847. }
  3848. return ptr == end ? 0 : +1;
  3849. }
  3850. static ufbxi_forceinline bool ufbxi_starts_with(ufbx_string str, ufbx_string prefix)
  3851. {
  3852. return str.length >= prefix.length && !memcmp(str.data, prefix.data, prefix.length);
  3853. }
  3854. static ufbxi_forceinline bool ufbxi_ends_with(ufbx_string str, ufbx_string suffix)
  3855. {
  3856. return str.length >= suffix.length && !memcmp(str.data + str.length - suffix.length, suffix.data, suffix.length);
  3857. }
  3858. static ufbxi_noinline bool ufbxi_remove_prefix_len(ufbx_string *str, const char *prefix, size_t prefix_len)
  3859. {
  3860. ufbx_string prefix_str = { prefix, prefix_len };
  3861. if (ufbxi_starts_with(*str, prefix_str)) {
  3862. str->data += prefix_len;
  3863. str->length -= prefix_len;
  3864. return true;
  3865. }
  3866. return false;
  3867. }
  3868. static ufbxi_noinline bool ufbxi_remove_suffix_len(ufbx_string *str, const char *suffix, size_t suffix_len)
  3869. {
  3870. ufbx_string suffix_str = { suffix, suffix_len };
  3871. if (ufbxi_ends_with(*str, suffix_str)) {
  3872. str->length -= suffix_len;
  3873. return true;
  3874. }
  3875. return false;
  3876. }
  3877. static ufbxi_forceinline bool ufbxi_remove_prefix_str(ufbx_string *str, ufbx_string prefix)
  3878. {
  3879. return ufbxi_remove_prefix_len(str, prefix.data, prefix.length);
  3880. }
  3881. static ufbxi_forceinline bool ufbxi_remove_suffix_c(ufbx_string *str, const char *suffix)
  3882. {
  3883. return ufbxi_remove_suffix_len(str, suffix, strlen(suffix));
  3884. }
  3885. static int ufbxi_map_cmp_string(void *user, const void *va, const void *vb)
  3886. {
  3887. (void)user;
  3888. const ufbx_string *a = (const ufbx_string*)va, *b = (const ufbx_string*)vb;
  3889. return ufbxi_str_cmp(*a, *b);
  3890. }
  3891. static ufbxi_forceinline ufbx_string ufbxi_safe_string(const char *data, size_t length)
  3892. {
  3893. ufbx_string str = { length > 0 ? data : ufbxi_empty_char, length };
  3894. return str;
  3895. }
  3896. static void ufbxi_string_pool_temp_free(ufbxi_string_pool *pool)
  3897. {
  3898. ufbxi_free(pool->map.ator, char, pool->temp_str, pool->temp_cap);
  3899. ufbxi_map_free(&pool->map);
  3900. }
  3901. ufbxi_nodiscard static size_t ufbxi_add_replacement_char(ufbxi_string_pool *pool, char *dst, char c)
  3902. {
  3903. switch (pool->error_handling) {
  3904. case UFBX_UNICODE_ERROR_HANDLING_REPLACEMENT_CHARACTER:
  3905. dst[0] = (char)(uint8_t)0xefu;
  3906. dst[1] = (char)(uint8_t)0xbfu;
  3907. dst[2] = (char)(uint8_t)0xbdu;
  3908. return 3;
  3909. case UFBX_UNICODE_ERROR_HANDLING_UNDERSCORE:
  3910. dst[0] = '_';
  3911. return 1;
  3912. case UFBX_UNICODE_ERROR_HANDLING_QUESTION_MARK:
  3913. dst[0] = '?';
  3914. return 1;
  3915. case UFBX_UNICODE_ERROR_HANDLING_REMOVE:
  3916. return 0;
  3917. case UFBX_UNICODE_ERROR_HANDLING_UNSAFE_IGNORE:
  3918. dst[0] = c;
  3919. return 1;
  3920. default:
  3921. return 0;
  3922. }
  3923. }
  3924. ufbxi_nodiscard static ufbxi_noinline int ufbxi_sanitize_string(ufbxi_string_pool *pool, ufbxi_sanitized_string *sanitized, const char *str, size_t length, size_t valid_length, bool push_both)
  3925. {
  3926. // Handle only invalid cases here
  3927. ufbx_assert(valid_length < length);
  3928. ufbxi_check_err_msg(pool->error, pool->error_handling != UFBX_UNICODE_ERROR_HANDLING_ABORT_LOADING, "Invalid UTF-8");
  3929. ufbxi_check_err(pool->error, ufbxi_warnf_imp(pool->warnings, UFBX_WARNING_BAD_UNICODE, ~0u, "Bad UTF-8 string"));
  3930. size_t index = valid_length;
  3931. size_t dst_len = index;
  3932. if (push_both) {
  3933. // Copy both the full raw string and the initial valid part
  3934. ufbxi_check_err(pool->error, length <= SIZE_MAX / 2 - 64);
  3935. ufbxi_check_err(pool->error, ufbxi_grow_array(pool->map.ator, &pool->temp_str, &pool->temp_cap, length * 2 + 64));
  3936. memcpy(pool->temp_str, str, length);
  3937. pool->temp_str[length] = '\0';
  3938. memcpy(pool->temp_str + length + 1, str, index);
  3939. dst_len += length + 1;
  3940. } else {
  3941. // Copy the initial valid part
  3942. ufbxi_check_err(pool->error, length <= SIZE_MAX - 64);
  3943. ufbxi_check_err(pool->error, ufbxi_grow_array(pool->map.ator, &pool->temp_str, &pool->temp_cap, length + 64));
  3944. memcpy(pool->temp_str, str, index);
  3945. }
  3946. char *dst = pool->temp_str;
  3947. while (index < length) {
  3948. uint8_t c = (uint8_t)str[index];
  3949. size_t left = length - index;
  3950. // Not optimal but not the worst thing ever
  3951. if (pool->temp_cap - dst_len < 16) {
  3952. ufbxi_check_err(pool->error, ufbxi_grow_array(pool->map.ator, &pool->temp_str, &pool->temp_cap, dst_len + 16));
  3953. dst = pool->temp_str;
  3954. }
  3955. if ((c & 0x80) == 0) {
  3956. if (c != 0) {
  3957. dst[dst_len] = (char)c;
  3958. dst_len += 1;
  3959. index += 1;
  3960. continue;
  3961. }
  3962. } else if ((c & 0xe0) == 0xc0 && left >= 2) {
  3963. uint8_t t0 = (uint8_t)str[index + 1];
  3964. uint32_t code = (uint32_t)c << 8 | (uint32_t)t0 << 0;
  3965. if ((code & 0xc0) == 0x80 && code >= 0xc280) {
  3966. dst[dst_len + 0] = (char)c;
  3967. dst[dst_len + 1] = (char)t0;
  3968. dst_len += 2;
  3969. index += 2;
  3970. continue;
  3971. }
  3972. } else if ((c & 0xf0) == 0xe0 && left >= 3) {
  3973. uint8_t t0 = (uint8_t)str[index + 1], t1 = (uint8_t)str[index + 2];
  3974. uint32_t code = (uint32_t)c << 16 | (uint32_t)t0 << 8 | (uint32_t)t1;
  3975. if ((code & 0xc0c0) == 0x8080 && code >= 0xe0a080 && (code < 0xeda080 || code >= 0xee8080)) {
  3976. dst[dst_len + 0] = (char)c;
  3977. dst[dst_len + 1] = (char)t0;
  3978. dst[dst_len + 2] = (char)t1;
  3979. dst_len += 3;
  3980. index += 3;
  3981. continue;
  3982. }
  3983. } else if ((c & 0xf8) == 0xf0 && left >= 4) {
  3984. uint8_t t0 = (uint8_t)str[index + 1], t1 = (uint8_t)str[index + 2], t2 = (uint8_t)str[index + 3];
  3985. uint32_t code = (uint32_t)c << 24 | (uint32_t)t0 << 16 | (uint32_t)t1 << 8 | (uint32_t)t2;
  3986. if ((code & 0xc0c0c0) == 0x808080 && code >= 0xf0908080u && code <= 0xf48fbfbfu) {
  3987. dst[dst_len + 0] = (char)c;
  3988. dst[dst_len + 1] = (char)t0;
  3989. dst[dst_len + 2] = (char)t1;
  3990. dst[dst_len + 3] = (char)t2;
  3991. dst_len += 4;
  3992. index += 4;
  3993. continue;
  3994. }
  3995. }
  3996. dst_len += ufbxi_add_replacement_char(pool, dst + dst_len, (char)c);
  3997. index++;
  3998. }
  3999. // Sanitized strings are packed to 32-bit integers, in practice this should be fine
  4000. // as strings are limited to 32-bit length in FBX itself.
  4001. // The only problem case is a massive string that is full of unicode errors, ie.
  4002. // >1GB binary blob, but these should never be sanitized.
  4003. ufbxi_check_err(pool->error, length <= UINT32_MAX);
  4004. sanitized->raw_data = pool->temp_str;
  4005. if (push_both) {
  4006. // Reserve `UINT32_MAX` for invalid UTF-8 without sanitization
  4007. size_t utf8_length = dst_len - (length + 1);
  4008. ufbxi_check_err(pool->error, utf8_length < UINT32_MAX);
  4009. sanitized->raw_length = (uint32_t)length;
  4010. sanitized->utf8_length = (uint32_t)utf8_length;
  4011. } else {
  4012. ufbxi_check_err(pool->error, dst_len <= UINT32_MAX);
  4013. sanitized->raw_length = (uint32_t)dst_len;
  4014. sanitized->utf8_length = 0;
  4015. }
  4016. return 1;
  4017. }
  4018. ufbxi_nodiscard static ufbxi_noinline int ufbxi_push_sanitized_string(ufbxi_string_pool *pool, ufbxi_sanitized_string *sanitized, const char *str, size_t length, uint32_t hash, bool raw)
  4019. {
  4020. ufbxi_regression_assert(hash == ufbxi_hash_string(str, length));
  4021. ufbxi_check_err(pool->error, length <= UINT32_MAX);
  4022. ufbxi_check_err(pool->error, ufbxi_map_grow(&pool->map, ufbx_string, pool->initial_size));
  4023. const char *total_data = str;
  4024. size_t total_length = length;
  4025. sanitized->raw_length = (uint32_t)length;
  4026. sanitized->utf8_length = 0;
  4027. if (!raw) {
  4028. size_t valid_length = ufbxi_utf8_valid_length(str, length);
  4029. if (valid_length != length) {
  4030. ufbxi_check_err(pool->error, ufbxi_sanitize_string(pool, sanitized, str, length, valid_length, true));
  4031. total_data = sanitized->raw_data;
  4032. total_length = sanitized->raw_length + sanitized->utf8_length + 1;
  4033. hash = ufbxi_hash_string(str, length);
  4034. }
  4035. }
  4036. ufbx_string ref = { total_data, total_length };
  4037. ufbx_string *entry = ufbxi_map_find(&pool->map, ufbx_string, hash, &ref);
  4038. if (entry) {
  4039. sanitized->raw_data = entry->data;
  4040. } else {
  4041. entry = ufbxi_map_insert(&pool->map, ufbx_string, hash, &ref);
  4042. ufbxi_check_err(pool->error, entry);
  4043. entry->length = total_length;
  4044. char *dst = ufbxi_push(&pool->buf, char, total_length + 1);
  4045. ufbxi_check_err(pool->error, dst);
  4046. memcpy(dst, total_data, total_length);
  4047. dst[total_length] = '\0';
  4048. entry->data = dst;
  4049. sanitized->raw_data = dst;
  4050. }
  4051. return 1;
  4052. }
  4053. ufbxi_nodiscard static ufbxi_noinline const char *ufbxi_push_string_imp(ufbxi_string_pool *pool, const char *str, size_t length, size_t *p_out_length, bool copy, bool raw)
  4054. {
  4055. if (length == 0) return ufbxi_empty_char;
  4056. ufbxi_check_return_err(pool->error, ufbxi_map_grow(&pool->map, ufbx_string, pool->initial_size), NULL);
  4057. uint32_t hash;
  4058. if (raw) {
  4059. hash = ufbxi_hash_string(str, length);
  4060. } else {
  4061. bool non_ascii = false;
  4062. hash = ufbxi_hash_string_check_ascii(str, length, &non_ascii);
  4063. if (non_ascii) {
  4064. size_t valid_length = ufbxi_utf8_valid_length(str, length);
  4065. if (valid_length < length) {
  4066. ufbxi_sanitized_string sanitized;
  4067. ufbxi_check_return_err(pool->error, ufbxi_sanitize_string(pool, &sanitized, str, length, valid_length, false), NULL);
  4068. str = sanitized.raw_data;
  4069. length = sanitized.raw_length;
  4070. hash = ufbxi_hash_string(str, length);
  4071. *p_out_length = length;
  4072. }
  4073. }
  4074. }
  4075. ufbx_string ref = { str, length };
  4076. ufbx_string *entry = ufbxi_map_find(&pool->map, ufbx_string, hash, &ref);
  4077. if (entry) return entry->data;
  4078. entry = ufbxi_map_insert(&pool->map, ufbx_string, hash, &ref);
  4079. ufbxi_check_return_err(pool->error, entry, NULL);
  4080. entry->length = length;
  4081. if (copy) {
  4082. char *dst = ufbxi_push(&pool->buf, char, length + 1);
  4083. ufbxi_check_return_err(pool->error, dst, NULL);
  4084. memcpy(dst, str, length);
  4085. dst[length] = '\0';
  4086. entry->data = dst;
  4087. } else {
  4088. entry->data = str;
  4089. }
  4090. return entry->data;
  4091. }
  4092. ufbxi_nodiscard static ufbxi_forceinline const char *ufbxi_push_string(ufbxi_string_pool *pool, const char *str, size_t length, size_t *p_out_length, bool raw)
  4093. {
  4094. return ufbxi_push_string_imp(pool, str, length, p_out_length, true, raw);
  4095. }
  4096. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_push_string_place(ufbxi_string_pool *pool, const char **p_str, size_t *p_length, bool raw)
  4097. {
  4098. const char *str = *p_str;
  4099. size_t length = *p_length;
  4100. ufbxi_check_err(pool->error, str || length == 0);
  4101. str = ufbxi_push_string(pool, str, length, p_length, raw);
  4102. ufbxi_check_err(pool->error, str);
  4103. *p_str = str;
  4104. return 1;
  4105. }
  4106. ufbxi_nodiscard static ufbxi_noinline int ufbxi_push_string_place_str(ufbxi_string_pool *pool, ufbx_string *p_str, bool raw)
  4107. {
  4108. ufbxi_check_err(pool->error, p_str);
  4109. return ufbxi_push_string_place(pool, &p_str->data, &p_str->length, raw);
  4110. }
  4111. ufbxi_nodiscard static ufbxi_noinline int ufbxi_push_string_place_blob(ufbxi_string_pool *pool, ufbx_blob *p_blob, bool raw)
  4112. {
  4113. if (p_blob->size == 0) {
  4114. p_blob->data = NULL;
  4115. return 1;
  4116. }
  4117. p_blob->data = ufbxi_push_string(pool, (const char*)p_blob->data, p_blob->size, &p_blob->size, raw);
  4118. ufbxi_check_err(pool->error, p_blob->data);
  4119. return 1;
  4120. }
  4121. // -- String constants
  4122. //
  4123. // All strings in FBX files are pooled so by having canonical string constant
  4124. // addresses we can compare strings to these constants by comparing pointers.
  4125. // Keep the list alphabetically sorted!
  4126. static const char ufbxi_AllSame[] = "AllSame";
  4127. static const char ufbxi_Alphas[] = "Alphas";
  4128. static const char ufbxi_AmbientColor[] = "AmbientColor";
  4129. static const char ufbxi_AnimationCurveNode[] = "AnimationCurveNode";
  4130. static const char ufbxi_AnimationCurve[] = "AnimationCurve";
  4131. static const char ufbxi_AnimationLayer[] = "AnimationLayer";
  4132. static const char ufbxi_AnimationStack[] = "AnimationStack";
  4133. static const char ufbxi_ApertureFormat[] = "ApertureFormat";
  4134. static const char ufbxi_ApertureMode[] = "ApertureMode";
  4135. static const char ufbxi_AreaLightShape[] = "AreaLightShape";
  4136. static const char ufbxi_AspectH[] = "AspectH";
  4137. static const char ufbxi_AspectHeight[] = "AspectHeight";
  4138. static const char ufbxi_AspectRatioMode[] = "AspectRatioMode";
  4139. static const char ufbxi_AspectW[] = "AspectW";
  4140. static const char ufbxi_AspectWidth[] = "AspectWidth";
  4141. static const char ufbxi_Audio[] = "Audio";
  4142. static const char ufbxi_AudioLayer[] = "AudioLayer";
  4143. static const char ufbxi_BaseLayer[] = "BaseLayer";
  4144. static const char ufbxi_BinaryData[] = "BinaryData";
  4145. static const char ufbxi_BindPose[] = "BindPose";
  4146. static const char ufbxi_BindingTable[] = "BindingTable";
  4147. static const char ufbxi_Binormals[] = "Binormals";
  4148. static const char ufbxi_BinormalsIndex[] = "BinormalsIndex";
  4149. static const char ufbxi_BinormalsW[] = "BinormalsW";
  4150. static const char ufbxi_BlendMode[] = "BlendMode";
  4151. static const char ufbxi_BlendModes[] = "BlendModes";
  4152. static const char ufbxi_BlendShapeChannel[] = "BlendShapeChannel";
  4153. static const char ufbxi_BlendShape[] = "BlendShape";
  4154. static const char ufbxi_BlendWeights[] = "BlendWeights";
  4155. static const char ufbxi_BoundaryRule[] = "BoundaryRule";
  4156. static const char ufbxi_Boundary[] = "Boundary";
  4157. static const char ufbxi_ByEdge[] = "ByEdge";
  4158. static const char ufbxi_ByPolygonVertex[] = "ByPolygonVertex";
  4159. static const char ufbxi_ByPolygon[] = "ByPolygon";
  4160. static const char ufbxi_ByVertex[] = "ByVertex";
  4161. static const char ufbxi_ByVertice[] = "ByVertice";
  4162. static const char ufbxi_Cache[] = "Cache";
  4163. static const char ufbxi_CameraProjectionType[] = "CameraProjectionType";
  4164. static const char ufbxi_CameraStereo[] = "CameraStereo";
  4165. static const char ufbxi_CameraSwitcher[] = "CameraSwitcher";
  4166. static const char ufbxi_Camera[] = "Camera";
  4167. static const char ufbxi_CastLight[] = "CastLight";
  4168. static const char ufbxi_CastShadows[] = "CastShadows";
  4169. static const char ufbxi_Channel[] = "Channel";
  4170. static const char ufbxi_Character[] = "Character";
  4171. static const char ufbxi_Children[] = "Children";
  4172. static const char ufbxi_Cluster[] = "Cluster";
  4173. static const char ufbxi_CollectionExclusive[] = "CollectionExclusive";
  4174. static const char ufbxi_Collection[] = "Collection";
  4175. static const char ufbxi_ColorIndex[] = "ColorIndex";
  4176. static const char ufbxi_Color[] = "Color";
  4177. static const char ufbxi_Colors[] = "Colors";
  4178. static const char ufbxi_Cone_angle[] = "Cone angle";
  4179. static const char ufbxi_ConeAngle[] = "ConeAngle";
  4180. static const char ufbxi_Connections[] = "Connections";
  4181. static const char ufbxi_Constraint[] = "Constraint";
  4182. static const char ufbxi_Content[] = "Content";
  4183. static const char ufbxi_CoordAxisSign[] = "CoordAxisSign";
  4184. static const char ufbxi_CoordAxis[] = "CoordAxis";
  4185. static const char ufbxi_Count[] = "Count";
  4186. static const char ufbxi_Creator[] = "Creator";
  4187. static const char ufbxi_CurrentTextureBlendMode[] = "CurrentTextureBlendMode";
  4188. static const char ufbxi_CurrentTimeMarker[] = "CurrentTimeMarker";
  4189. static const char ufbxi_CustomFrameRate[] = "CustomFrameRate";
  4190. static const char ufbxi_DecayType[] = "DecayType";
  4191. static const char ufbxi_DefaultCamera[] = "DefaultCamera";
  4192. static const char ufbxi_Default[] = "Default";
  4193. static const char ufbxi_Definitions[] = "Definitions";
  4194. static const char ufbxi_DeformPercent[] = "DeformPercent";
  4195. static const char ufbxi_Deformer[] = "Deformer";
  4196. static const char ufbxi_DiffuseColor[] = "DiffuseColor";
  4197. static const char ufbxi_Dimension[] = "Dimension";
  4198. static const char ufbxi_Dimensions[] = "Dimensions";
  4199. static const char ufbxi_DisplayLayer[] = "DisplayLayer";
  4200. static const char ufbxi_Document[] = "Document";
  4201. static const char ufbxi_Documents[] = "Documents";
  4202. static const char ufbxi_EdgeCrease[] = "EdgeCrease";
  4203. static const char ufbxi_EdgeIndexArray[] = "EdgeIndexArray";
  4204. static const char ufbxi_Edges[] = "Edges";
  4205. static const char ufbxi_EmissiveColor[] = "EmissiveColor";
  4206. static const char ufbxi_Entry[] = "Entry";
  4207. static const char ufbxi_FBXHeaderExtension[] = "FBXHeaderExtension";
  4208. static const char ufbxi_FBXVersion[] = "FBXVersion";
  4209. static const char ufbxi_FKEffector[] = "FKEffector";
  4210. static const char ufbxi_FarPlane[] = "FarPlane";
  4211. static const char ufbxi_FbxPropertyEntry[] = "FbxPropertyEntry";
  4212. static const char ufbxi_FbxSemanticEntry[] = "FbxSemanticEntry";
  4213. static const char ufbxi_FieldOfViewX[] = "FieldOfViewX";
  4214. static const char ufbxi_FieldOfViewY[] = "FieldOfViewY";
  4215. static const char ufbxi_FieldOfView[] = "FieldOfView";
  4216. static const char ufbxi_FileName[] = "FileName";
  4217. static const char ufbxi_Filename[] = "Filename";
  4218. static const char ufbxi_FilmHeight[] = "FilmHeight";
  4219. static const char ufbxi_FilmSqueezeRatio[] = "FilmSqueezeRatio";
  4220. static const char ufbxi_FilmWidth[] = "FilmWidth";
  4221. static const char ufbxi_FlipNormals[] = "FlipNormals";
  4222. static const char ufbxi_FocalLength[] = "FocalLength";
  4223. static const char ufbxi_Form[] = "Form";
  4224. static const char ufbxi_Freeze[] = "Freeze";
  4225. static const char ufbxi_FrontAxisSign[] = "FrontAxisSign";
  4226. static const char ufbxi_FrontAxis[] = "FrontAxis";
  4227. static const char ufbxi_FullWeights[] = "FullWeights";
  4228. static const char ufbxi_GateFit[] = "GateFit";
  4229. static const char ufbxi_GeometricRotation[] = "GeometricRotation";
  4230. static const char ufbxi_GeometricScaling[] = "GeometricScaling";
  4231. static const char ufbxi_GeometricTranslation[] = "GeometricTranslation";
  4232. static const char ufbxi_GeometryUVInfo[] = "GeometryUVInfo";
  4233. static const char ufbxi_Geometry[] = "Geometry";
  4234. static const char ufbxi_GlobalSettings[] = "GlobalSettings";
  4235. static const char ufbxi_Hole[] = "Hole";
  4236. static const char ufbxi_HotSpot[] = "HotSpot";
  4237. static const char ufbxi_IKEffector[] = "IKEffector";
  4238. static const char ufbxi_ImageData[] = "ImageData";
  4239. static const char ufbxi_Implementation[] = "Implementation";
  4240. static const char ufbxi_Indexes[] = "Indexes";
  4241. static const char ufbxi_InheritType[] = "InheritType";
  4242. static const char ufbxi_InnerAngle[] = "InnerAngle";
  4243. static const char ufbxi_Intensity[] = "Intensity";
  4244. static const char ufbxi_IsTheNodeInSet[] = "IsTheNodeInSet";
  4245. static const char ufbxi_KeyAttrDataFloat[] = "KeyAttrDataFloat";
  4246. static const char ufbxi_KeyAttrFlags[] = "KeyAttrFlags";
  4247. static const char ufbxi_KeyAttrRefCount[] = "KeyAttrRefCount";
  4248. static const char ufbxi_KeyCount[] = "KeyCount";
  4249. static const char ufbxi_KeyTime[] = "KeyTime";
  4250. static const char ufbxi_KeyValueFloat[] = "KeyValueFloat";
  4251. static const char ufbxi_Key[] = "Key";
  4252. static const char ufbxi_KnotVectorU[] = "KnotVectorU";
  4253. static const char ufbxi_KnotVectorV[] = "KnotVectorV";
  4254. static const char ufbxi_KnotVector[] = "KnotVector";
  4255. static const char ufbxi_LayerElementBinormal[] = "LayerElementBinormal";
  4256. static const char ufbxi_LayerElementColor[] = "LayerElementColor";
  4257. static const char ufbxi_LayerElementEdgeCrease[] = "LayerElementEdgeCrease";
  4258. static const char ufbxi_LayerElementHole[] = "LayerElementHole";
  4259. static const char ufbxi_LayerElementMaterial[] = "LayerElementMaterial";
  4260. static const char ufbxi_LayerElementNormal[] = "LayerElementNormal";
  4261. static const char ufbxi_LayerElementPolygonGroup[] = "LayerElementPolygonGroup";
  4262. static const char ufbxi_LayerElementSmoothing[] = "LayerElementSmoothing";
  4263. static const char ufbxi_LayerElementTangent[] = "LayerElementTangent";
  4264. static const char ufbxi_LayerElementUV[] = "LayerElementUV";
  4265. static const char ufbxi_LayerElementVertexCrease[] = "LayerElementVertexCrease";
  4266. static const char ufbxi_LayerElementVisibility[] = "LayerElementVisibility";
  4267. static const char ufbxi_LayerElement[] = "LayerElement";
  4268. static const char ufbxi_Layer[] = "Layer";
  4269. static const char ufbxi_LayeredTexture[] = "LayeredTexture";
  4270. static const char ufbxi_Lcl_Rotation[] = "Lcl Rotation";
  4271. static const char ufbxi_Lcl_Scaling[] = "Lcl Scaling";
  4272. static const char ufbxi_Lcl_Translation[] = "Lcl Translation";
  4273. static const char ufbxi_LeftCamera[] = "LeftCamera";
  4274. static const char ufbxi_LightType[] = "LightType";
  4275. static const char ufbxi_Light[] = "Light";
  4276. static const char ufbxi_LimbLength[] = "LimbLength";
  4277. static const char ufbxi_LimbNode[] = "LimbNode";
  4278. static const char ufbxi_Limb[] = "Limb";
  4279. static const char ufbxi_Line[] = "Line";
  4280. static const char ufbxi_Link[] = "Link";
  4281. static const char ufbxi_LocalStart[] = "LocalStart";
  4282. static const char ufbxi_LocalStop[] = "LocalStop";
  4283. static const char ufbxi_LocalTime[] = "LocalTime";
  4284. static const char ufbxi_LodGroup[] = "LodGroup";
  4285. static const char ufbxi_MappingInformationType[] = "MappingInformationType";
  4286. static const char ufbxi_Marker[] = "Marker";
  4287. static const char ufbxi_MaterialAssignation[] = "MaterialAssignation";
  4288. static const char ufbxi_Material[] = "Material";
  4289. static const char ufbxi_Materials[] = "Materials";
  4290. static const char ufbxi_Matrix[] = "Matrix";
  4291. static const char ufbxi_Media[] = "Media";
  4292. static const char ufbxi_Mesh[] = "Mesh";
  4293. static const char ufbxi_Model[] = "Model";
  4294. static const char ufbxi_Name[] = "Name";
  4295. static const char ufbxi_NearPlane[] = "NearPlane";
  4296. static const char ufbxi_NodeAttributeName[] = "NodeAttributeName";
  4297. static const char ufbxi_NodeAttribute[] = "NodeAttribute";
  4298. static const char ufbxi_Node[] = "Node";
  4299. static const char ufbxi_Normals[] = "Normals";
  4300. static const char ufbxi_NormalsIndex[] = "NormalsIndex";
  4301. static const char ufbxi_NormalsW[] = "NormalsW";
  4302. static const char ufbxi_Null[] = "Null";
  4303. static const char ufbxi_NurbsCurve[] = "NurbsCurve";
  4304. static const char ufbxi_NurbsSurfaceOrder[] = "NurbsSurfaceOrder";
  4305. static const char ufbxi_NurbsSurface[] = "NurbsSurface";
  4306. static const char ufbxi_Nurbs[] = "Nurbs";
  4307. static const char ufbxi_OO[] = "OO\0";
  4308. static const char ufbxi_OP[] = "OP\0";
  4309. static const char ufbxi_ObjectMetaData[] = "ObjectMetaData";
  4310. static const char ufbxi_ObjectType[] = "ObjectType";
  4311. static const char ufbxi_Objects[] = "Objects";
  4312. static const char ufbxi_Order[] = "Order";
  4313. static const char ufbxi_OriginalUnitScaleFactor[] = "OriginalUnitScaleFactor";
  4314. static const char ufbxi_OriginalUpAxis[] = "OriginalUpAxis";
  4315. static const char ufbxi_OriginalUpAxisSign[] = "OriginalUpAxisSign";
  4316. static const char ufbxi_OrthoZoom[] = "OrthoZoom";
  4317. static const char ufbxi_OuterAngle[] = "OuterAngle";
  4318. static const char ufbxi_PO[] = "PO\0";
  4319. static const char ufbxi_PP[] = "PP\0";
  4320. static const char ufbxi_PointsIndex[] = "PointsIndex";
  4321. static const char ufbxi_Points[] = "Points";
  4322. static const char ufbxi_PolygonGroup[] = "PolygonGroup";
  4323. static const char ufbxi_PolygonIndexArray[] = "PolygonIndexArray";
  4324. static const char ufbxi_PolygonVertexIndex[] = "PolygonVertexIndex";
  4325. static const char ufbxi_PoseNode[] = "PoseNode";
  4326. static const char ufbxi_Pose[] = "Pose";
  4327. static const char ufbxi_PostRotation[] = "PostRotation";
  4328. static const char ufbxi_PreRotation[] = "PreRotation";
  4329. static const char ufbxi_PreviewDivisionLevels[] = "PreviewDivisionLevels";
  4330. static const char ufbxi_Properties60[] = "Properties60";
  4331. static const char ufbxi_Properties70[] = "Properties70";
  4332. static const char ufbxi_PropertyTemplate[] = "PropertyTemplate";
  4333. static const char ufbxi_R[] = "R\0\0";
  4334. static const char ufbxi_ReferenceStart[] = "ReferenceStart";
  4335. static const char ufbxi_ReferenceStop[] = "ReferenceStop";
  4336. static const char ufbxi_ReferenceTime[] = "ReferenceTime";
  4337. static const char ufbxi_RelativeFileName[] = "RelativeFileName";
  4338. static const char ufbxi_RelativeFilename[] = "RelativeFilename";
  4339. static const char ufbxi_RenderDivisionLevels[] = "RenderDivisionLevels";
  4340. static const char ufbxi_RightCamera[] = "RightCamera";
  4341. static const char ufbxi_RootNode[] = "RootNode";
  4342. static const char ufbxi_Root[] = "Root";
  4343. static const char ufbxi_RotationAccumulationMode[] = "RotationAccumulationMode";
  4344. static const char ufbxi_RotationOffset[] = "RotationOffset";
  4345. static const char ufbxi_RotationOrder[] = "RotationOrder";
  4346. static const char ufbxi_RotationPivot[] = "RotationPivot";
  4347. static const char ufbxi_Rotation[] = "Rotation";
  4348. static const char ufbxi_S[] = "S\0\0";
  4349. static const char ufbxi_ScaleAccumulationMode[] = "ScaleAccumulationMode";
  4350. static const char ufbxi_ScalingOffset[] = "ScalingOffset";
  4351. static const char ufbxi_ScalingPivot[] = "ScalingPivot";
  4352. static const char ufbxi_Scaling[] = "Scaling";
  4353. static const char ufbxi_SceneInfo[] = "SceneInfo";
  4354. static const char ufbxi_SelectionNode[] = "SelectionNode";
  4355. static const char ufbxi_SelectionSet[] = "SelectionSet";
  4356. static const char ufbxi_ShadingModel[] = "ShadingModel";
  4357. static const char ufbxi_Shape[] = "Shape";
  4358. static const char ufbxi_Shininess[] = "Shininess";
  4359. static const char ufbxi_Show[] = "Show";
  4360. static const char ufbxi_Size[] = "Size";
  4361. static const char ufbxi_Skin[] = "Skin";
  4362. static const char ufbxi_SkinningType[] = "SkinningType";
  4363. static const char ufbxi_Smoothing[] = "Smoothing";
  4364. static const char ufbxi_Smoothness[] = "Smoothness";
  4365. static const char ufbxi_SnapOnFrameMode[] = "SnapOnFrameMode";
  4366. static const char ufbxi_SpecularColor[] = "SpecularColor";
  4367. static const char ufbxi_Step[] = "Step";
  4368. static const char ufbxi_SubDeformer[] = "SubDeformer";
  4369. static const char ufbxi_T[] = "T\0\0";
  4370. static const char ufbxi_Take[] = "Take";
  4371. static const char ufbxi_Takes[] = "Takes";
  4372. static const char ufbxi_Tangents[] = "Tangents";
  4373. static const char ufbxi_TangentsIndex[] = "TangentsIndex";
  4374. static const char ufbxi_TangentsW[] = "TangentsW";
  4375. static const char ufbxi_Texture[] = "Texture";
  4376. static const char ufbxi_Texture_alpha[] = "Texture alpha";
  4377. static const char ufbxi_TextureId[] = "TextureId";
  4378. static const char ufbxi_TextureRotationPivot[] = "TextureRotationPivot";
  4379. static const char ufbxi_TextureScalingPivot[] = "TextureScalingPivot";
  4380. static const char ufbxi_TextureUV[] = "TextureUV";
  4381. static const char ufbxi_TextureUVVerticeIndex[] = "TextureUVVerticeIndex";
  4382. static const char ufbxi_Thumbnail[] = "Thumbnail";
  4383. static const char ufbxi_TimeMarker[] = "TimeMarker";
  4384. static const char ufbxi_TimeMode[] = "TimeMode";
  4385. static const char ufbxi_TimeProtocol[] = "TimeProtocol";
  4386. static const char ufbxi_TimeSpanStart[] = "TimeSpanStart";
  4387. static const char ufbxi_TimeSpanStop[] = "TimeSpanStop";
  4388. static const char ufbxi_TransformLink[] = "TransformLink";
  4389. static const char ufbxi_Transform[] = "Transform";
  4390. static const char ufbxi_Translation[] = "Translation";
  4391. static const char ufbxi_TrimNurbsSurface[] = "TrimNurbsSurface";
  4392. static const char ufbxi_Type[] = "Type";
  4393. static const char ufbxi_TypedIndex[] = "TypedIndex";
  4394. static const char ufbxi_UVIndex[] = "UVIndex";
  4395. static const char ufbxi_UVSet[] = "UVSet";
  4396. static const char ufbxi_UVSwap[] = "UVSwap";
  4397. static const char ufbxi_UV[] = "UV\0";
  4398. static const char ufbxi_UnitScaleFactor[] = "UnitScaleFactor";
  4399. static const char ufbxi_UpAxisSign[] = "UpAxisSign";
  4400. static const char ufbxi_UpAxis[] = "UpAxis";
  4401. static const char ufbxi_Version5[] = "Version5";
  4402. static const char ufbxi_VertexCacheDeformer[] = "VertexCacheDeformer";
  4403. static const char ufbxi_VertexCrease[] = "VertexCrease";
  4404. static const char ufbxi_VertexCreaseIndex[] = "VertexCreaseIndex";
  4405. static const char ufbxi_VertexIndexArray[] = "VertexIndexArray";
  4406. static const char ufbxi_Vertices[] = "Vertices";
  4407. static const char ufbxi_Video[] = "Video";
  4408. static const char ufbxi_Visibility[] = "Visibility";
  4409. static const char ufbxi_Weight[] = "Weight";
  4410. static const char ufbxi_Weights[] = "Weights";
  4411. static const char ufbxi_WrapModeU[] = "WrapModeU";
  4412. static const char ufbxi_WrapModeV[] = "WrapModeV";
  4413. static const char ufbxi_X[] = "X\0\0";
  4414. static const char ufbxi_Y[] = "Y\0\0";
  4415. static const char ufbxi_Z[] = "Z\0\0";
  4416. static const char ufbxi_d_X[] = "d|X";
  4417. static const char ufbxi_d_Y[] = "d|Y";
  4418. static const char ufbxi_d_Z[] = "d|Z";
  4419. static const ufbx_string ufbxi_strings[] = {
  4420. { ufbxi_AllSame, 7 },
  4421. { ufbxi_Alphas, 6 },
  4422. { ufbxi_AmbientColor, 12 },
  4423. { ufbxi_AnimationCurve, 14 },
  4424. { ufbxi_AnimationCurveNode, 18 },
  4425. { ufbxi_AnimationLayer, 14 },
  4426. { ufbxi_AnimationStack, 14 },
  4427. { ufbxi_ApertureFormat, 14 },
  4428. { ufbxi_ApertureMode, 12 },
  4429. { ufbxi_AreaLightShape, 14 },
  4430. { ufbxi_AspectH, 7 },
  4431. { ufbxi_AspectHeight, 12 },
  4432. { ufbxi_AspectRatioMode, 15 },
  4433. { ufbxi_AspectW, 7 },
  4434. { ufbxi_AspectWidth, 11 },
  4435. { ufbxi_Audio, 5 },
  4436. { ufbxi_AudioLayer, 10 },
  4437. { ufbxi_BaseLayer, 9 },
  4438. { ufbxi_BinaryData, 10 },
  4439. { ufbxi_BindPose, 8 },
  4440. { ufbxi_BindingTable, 12 },
  4441. { ufbxi_Binormals, 9 },
  4442. { ufbxi_BinormalsIndex, 14 },
  4443. { ufbxi_BinormalsW, 10 },
  4444. { ufbxi_BlendMode, 9 },
  4445. { ufbxi_BlendModes, 10 },
  4446. { ufbxi_BlendShape, 10 },
  4447. { ufbxi_BlendShapeChannel, 17 },
  4448. { ufbxi_BlendWeights, 12 },
  4449. { ufbxi_Boundary, 8 },
  4450. { ufbxi_BoundaryRule, 12 },
  4451. { ufbxi_ByEdge, 6 },
  4452. { ufbxi_ByPolygon, 9 },
  4453. { ufbxi_ByPolygonVertex, 15 },
  4454. { ufbxi_ByVertex, 8 },
  4455. { ufbxi_ByVertice, 9 },
  4456. { ufbxi_Cache, 5 },
  4457. { ufbxi_Camera, 6 },
  4458. { ufbxi_CameraProjectionType, 20 },
  4459. { ufbxi_CameraStereo, 12 },
  4460. { ufbxi_CameraSwitcher, 14 },
  4461. { ufbxi_CastLight, 9 },
  4462. { ufbxi_CastShadows, 11 },
  4463. { ufbxi_Channel, 7 },
  4464. { ufbxi_Character, sizeof(ufbxi_Character) - 1 },
  4465. { ufbxi_Children, 8 },
  4466. { ufbxi_Cluster, 7 },
  4467. { ufbxi_Collection, 10 },
  4468. { ufbxi_CollectionExclusive, 19 },
  4469. { ufbxi_Color, 5 },
  4470. { ufbxi_ColorIndex, 10 },
  4471. { ufbxi_Colors, 6 },
  4472. { ufbxi_Cone_angle, 10 },
  4473. { ufbxi_ConeAngle, 9 },
  4474. { ufbxi_Connections, 11 },
  4475. { ufbxi_Constraint, sizeof(ufbxi_Constraint) - 1 },
  4476. { ufbxi_Content, 7 },
  4477. { ufbxi_CoordAxis, 9 },
  4478. { ufbxi_CoordAxisSign, 13 },
  4479. { ufbxi_Count, 5 },
  4480. { ufbxi_Creator, 7 },
  4481. { ufbxi_CurrentTextureBlendMode, 23 },
  4482. { ufbxi_CurrentTimeMarker, 17 },
  4483. { ufbxi_CustomFrameRate, 15 },
  4484. { ufbxi_DecayType, 9 },
  4485. { ufbxi_Default, 7 },
  4486. { ufbxi_DefaultCamera, 13 },
  4487. { ufbxi_Definitions, 11 },
  4488. { ufbxi_DeformPercent, 13 },
  4489. { ufbxi_Deformer, 8 },
  4490. { ufbxi_DiffuseColor, 12 },
  4491. { ufbxi_Dimension, 9 },
  4492. { ufbxi_Dimensions, 10 },
  4493. { ufbxi_DisplayLayer, 12 },
  4494. { ufbxi_Document, 8 },
  4495. { ufbxi_Documents, 9 },
  4496. { ufbxi_EdgeCrease, 10 },
  4497. { ufbxi_EdgeIndexArray, 14 },
  4498. { ufbxi_Edges, 5 },
  4499. { ufbxi_EmissiveColor, 13 },
  4500. { ufbxi_Entry, 5 },
  4501. { ufbxi_FBXHeaderExtension, 18 },
  4502. { ufbxi_FBXVersion, 10 },
  4503. { ufbxi_FKEffector, 10 },
  4504. { ufbxi_FarPlane, 8 },
  4505. { ufbxi_FbxPropertyEntry, 16 },
  4506. { ufbxi_FbxSemanticEntry, 16 },
  4507. { ufbxi_FieldOfView, 11 },
  4508. { ufbxi_FieldOfViewX, 12 },
  4509. { ufbxi_FieldOfViewY, 12 },
  4510. { ufbxi_FileName, 8 },
  4511. { ufbxi_Filename, 8 },
  4512. { ufbxi_FilmHeight, 10 },
  4513. { ufbxi_FilmSqueezeRatio, 16 },
  4514. { ufbxi_FilmWidth, 9 },
  4515. { ufbxi_FlipNormals, 11 },
  4516. { ufbxi_FocalLength, 11 },
  4517. { ufbxi_Form, 4 },
  4518. { ufbxi_Freeze, 6 },
  4519. { ufbxi_FrontAxis, 9 },
  4520. { ufbxi_FrontAxisSign, 13 },
  4521. { ufbxi_FullWeights, 11 },
  4522. { ufbxi_GateFit, 7 },
  4523. { ufbxi_GeometricRotation, 17 },
  4524. { ufbxi_GeometricScaling, 16 },
  4525. { ufbxi_GeometricTranslation, 20 },
  4526. { ufbxi_Geometry, 8 },
  4527. { ufbxi_GeometryUVInfo, 14 },
  4528. { ufbxi_GlobalSettings, 14 },
  4529. { ufbxi_Hole, 4 },
  4530. { ufbxi_HotSpot, 7 },
  4531. { ufbxi_IKEffector, 10 },
  4532. { ufbxi_ImageData, 9 },
  4533. { ufbxi_Implementation, 14 },
  4534. { ufbxi_Indexes, 7 },
  4535. { ufbxi_InheritType, 11 },
  4536. { ufbxi_InnerAngle, 10 },
  4537. { ufbxi_Intensity, 9 },
  4538. { ufbxi_IsTheNodeInSet, 14 },
  4539. { ufbxi_Key, 3 },
  4540. { ufbxi_KeyAttrDataFloat, 16 },
  4541. { ufbxi_KeyAttrFlags, 12 },
  4542. { ufbxi_KeyAttrRefCount, 15 },
  4543. { ufbxi_KeyCount, 8 },
  4544. { ufbxi_KeyTime, 7 },
  4545. { ufbxi_KeyValueFloat, 13 },
  4546. { ufbxi_KnotVector, 10 },
  4547. { ufbxi_KnotVectorU, 11 },
  4548. { ufbxi_KnotVectorV, 11 },
  4549. { ufbxi_Layer, 5 },
  4550. { ufbxi_LayerElement, 12 },
  4551. { ufbxi_LayerElementBinormal, 20 },
  4552. { ufbxi_LayerElementColor, 17 },
  4553. { ufbxi_LayerElementEdgeCrease, 22 },
  4554. { ufbxi_LayerElementHole, 16 },
  4555. { ufbxi_LayerElementMaterial, 20 },
  4556. { ufbxi_LayerElementNormal, 18 },
  4557. { ufbxi_LayerElementPolygonGroup, 24 },
  4558. { ufbxi_LayerElementSmoothing, 21 },
  4559. { ufbxi_LayerElementTangent, 19 },
  4560. { ufbxi_LayerElementUV, 14 },
  4561. { ufbxi_LayerElementVertexCrease, 24 },
  4562. { ufbxi_LayerElementVisibility, 22 },
  4563. { ufbxi_LayeredTexture, 14 },
  4564. { ufbxi_Lcl_Rotation, 12 },
  4565. { ufbxi_Lcl_Scaling, 11 },
  4566. { ufbxi_Lcl_Translation, 15 },
  4567. { ufbxi_LeftCamera, 10 },
  4568. { ufbxi_Light, 5 },
  4569. { ufbxi_LightType, 9 },
  4570. { ufbxi_Limb, 4 },
  4571. { ufbxi_LimbLength, 10 },
  4572. { ufbxi_LimbNode, 8 },
  4573. { ufbxi_Line, 4 },
  4574. { ufbxi_Link, 4 },
  4575. { ufbxi_LocalStart, 10 },
  4576. { ufbxi_LocalStop, 9 },
  4577. { ufbxi_LocalTime, 9 },
  4578. { ufbxi_LodGroup, 8 },
  4579. { ufbxi_MappingInformationType, 22 },
  4580. { ufbxi_Marker, 6 },
  4581. { ufbxi_Material, 8 },
  4582. { ufbxi_MaterialAssignation, 19 },
  4583. { ufbxi_Materials, 9 },
  4584. { ufbxi_Matrix, 6 },
  4585. { ufbxi_Media, 5 },
  4586. { ufbxi_Mesh, 4 },
  4587. { ufbxi_Model, 5 },
  4588. { ufbxi_Name, 4 },
  4589. { ufbxi_NearPlane, 9 },
  4590. { ufbxi_Node, 4 },
  4591. { ufbxi_NodeAttribute, 13 },
  4592. { ufbxi_NodeAttributeName, 17 },
  4593. { ufbxi_Normals, 7 },
  4594. { ufbxi_NormalsIndex, 12 },
  4595. { ufbxi_NormalsW, 8 },
  4596. { ufbxi_Null, 4 },
  4597. { ufbxi_Nurbs, 5 },
  4598. { ufbxi_NurbsCurve, 10 },
  4599. { ufbxi_NurbsSurface, 12 },
  4600. { ufbxi_NurbsSurfaceOrder, 17 },
  4601. { ufbxi_OO, 2 },
  4602. { ufbxi_OP, 2 },
  4603. { ufbxi_ObjectMetaData, 14 },
  4604. { ufbxi_ObjectType, 10 },
  4605. { ufbxi_Objects, 7 },
  4606. { ufbxi_Order, 5 },
  4607. { ufbxi_OriginalUnitScaleFactor, 23 },
  4608. { ufbxi_OriginalUpAxis, 14 },
  4609. { ufbxi_OriginalUpAxisSign, 18 },
  4610. { ufbxi_OrthoZoom, 9 },
  4611. { ufbxi_OuterAngle, 10 },
  4612. { ufbxi_PO, 2 },
  4613. { ufbxi_PP, 2 },
  4614. { ufbxi_Points, 6 },
  4615. { ufbxi_PointsIndex, 11 },
  4616. { ufbxi_PolygonGroup, 12 },
  4617. { ufbxi_PolygonIndexArray, 17 },
  4618. { ufbxi_PolygonVertexIndex, 18 },
  4619. { ufbxi_Pose, 4 },
  4620. { ufbxi_PoseNode, 8 },
  4621. { ufbxi_PostRotation, 12 },
  4622. { ufbxi_PreRotation, 11 },
  4623. { ufbxi_PreviewDivisionLevels, 21 },
  4624. { ufbxi_Properties60, 12 },
  4625. { ufbxi_Properties70, 12 },
  4626. { ufbxi_PropertyTemplate, 16 },
  4627. { ufbxi_R, 1 },
  4628. { ufbxi_ReferenceStart, 14 },
  4629. { ufbxi_ReferenceStop, 13 },
  4630. { ufbxi_ReferenceTime, 13 },
  4631. { ufbxi_RelativeFileName, 16 },
  4632. { ufbxi_RelativeFilename, 16 },
  4633. { ufbxi_RenderDivisionLevels, 20 },
  4634. { ufbxi_RightCamera, 11 },
  4635. { ufbxi_Root, 4 },
  4636. { ufbxi_RootNode, 8 },
  4637. { ufbxi_Rotation, 8 },
  4638. { ufbxi_RotationAccumulationMode, 24 },
  4639. { ufbxi_RotationOffset, 14 },
  4640. { ufbxi_RotationOrder, 13 },
  4641. { ufbxi_RotationPivot, 13 },
  4642. { ufbxi_S, 1 },
  4643. { ufbxi_ScaleAccumulationMode, 21 },
  4644. { ufbxi_Scaling, 7 },
  4645. { ufbxi_ScalingOffset, 13 },
  4646. { ufbxi_ScalingPivot, 12 },
  4647. { ufbxi_SceneInfo, 9 },
  4648. { ufbxi_SelectionNode, 13 },
  4649. { ufbxi_SelectionSet, 12 },
  4650. { ufbxi_ShadingModel, 12 },
  4651. { ufbxi_Shape, 5 },
  4652. { ufbxi_Shininess, 9 },
  4653. { ufbxi_Show, 4 },
  4654. { ufbxi_Size, 4 },
  4655. { ufbxi_Skin, 4 },
  4656. { ufbxi_SkinningType, 12 },
  4657. { ufbxi_Smoothing, 9 },
  4658. { ufbxi_Smoothness, 10 },
  4659. { ufbxi_SnapOnFrameMode, 15 },
  4660. { ufbxi_SpecularColor, 13 },
  4661. { ufbxi_Step, 4 },
  4662. { ufbxi_SubDeformer, 11 },
  4663. { ufbxi_T, 1 },
  4664. { ufbxi_Take, 4 },
  4665. { ufbxi_Takes, 5 },
  4666. { ufbxi_Tangents, 8 },
  4667. { ufbxi_TangentsIndex, 13 },
  4668. { ufbxi_TangentsW, 9 },
  4669. { ufbxi_Texture, 7 },
  4670. { ufbxi_Texture_alpha, 13 },
  4671. { ufbxi_TextureId, 9 },
  4672. { ufbxi_TextureRotationPivot, 20 },
  4673. { ufbxi_TextureScalingPivot, 19 },
  4674. { ufbxi_TextureUV, 9 },
  4675. { ufbxi_TextureUVVerticeIndex, 21 },
  4676. { ufbxi_Thumbnail, 9 },
  4677. { ufbxi_TimeMarker, 10 },
  4678. { ufbxi_TimeMode, 8 },
  4679. { ufbxi_TimeProtocol, 12 },
  4680. { ufbxi_TimeSpanStart, 13 },
  4681. { ufbxi_TimeSpanStop, 12 },
  4682. { ufbxi_Transform, 9 },
  4683. { ufbxi_TransformLink, 13 },
  4684. { ufbxi_Translation, 11 },
  4685. { ufbxi_TrimNurbsSurface, 16 },
  4686. { ufbxi_Type, 4 },
  4687. { ufbxi_TypedIndex, 10 },
  4688. { ufbxi_UV, 2 },
  4689. { ufbxi_UVIndex, 7 },
  4690. { ufbxi_UVSet, 5 },
  4691. { ufbxi_UVSwap, 6 },
  4692. { ufbxi_UnitScaleFactor, 15 },
  4693. { ufbxi_UpAxis, 6 },
  4694. { ufbxi_UpAxisSign, 10 },
  4695. { ufbxi_Version5, 8 },
  4696. { ufbxi_VertexCacheDeformer, 19 },
  4697. { ufbxi_VertexCrease, 12 },
  4698. { ufbxi_VertexCreaseIndex, 17 },
  4699. { ufbxi_VertexIndexArray, 16 },
  4700. { ufbxi_Vertices, 8 },
  4701. { ufbxi_Video, 5 },
  4702. { ufbxi_Visibility, 10 },
  4703. { ufbxi_Weight, 6 },
  4704. { ufbxi_Weights, 7 },
  4705. { ufbxi_WrapModeU, 9 },
  4706. { ufbxi_WrapModeV, 9 },
  4707. { ufbxi_X, 1 },
  4708. { ufbxi_Y, 1 },
  4709. { ufbxi_Z, 1 },
  4710. { ufbxi_d_X, 3 },
  4711. { ufbxi_d_Y, 3 },
  4712. { ufbxi_d_Z, 3 },
  4713. };
  4714. static const ufbx_vec3 ufbxi_one_vec3 = { 1.0f, 1.0f, 1.0f };
  4715. #define UFBXI_PI ((ufbx_real)3.14159265358979323846)
  4716. #define UFBXI_DPI (3.14159265358979323846)
  4717. #define UFBXI_DEG_TO_RAD ((ufbx_real)(UFBXI_PI / 180.0))
  4718. #define UFBXI_RAD_TO_DEG ((ufbx_real)(180.0 / UFBXI_PI))
  4719. #define UFBXI_DEG_TO_RAD_DOUBLE (UFBXI_DPI / 180.0)
  4720. #define UFBXI_RAD_TO_DEG_DOUBLE (180.0 / UFBXI_DPI)
  4721. #define UFBXI_MM_TO_INCH ((ufbx_real)0.0393700787)
  4722. ufbx_inline ufbx_vec3 ufbxi_add3(ufbx_vec3 a, ufbx_vec3 b) {
  4723. ufbx_vec3 v = { a.x + b.x, a.y + b.y, a.z + b.z };
  4724. return v;
  4725. }
  4726. ufbx_inline ufbx_vec3 ufbxi_sub3(ufbx_vec3 a, ufbx_vec3 b) {
  4727. ufbx_vec3 v = { a.x - b.x, a.y - b.y, a.z - b.z };
  4728. return v;
  4729. }
  4730. ufbx_inline ufbx_vec3 ufbxi_mul3(ufbx_vec3 a, ufbx_real b) {
  4731. ufbx_vec3 v = { a.x * b, a.y * b, a.z * b };
  4732. return v;
  4733. }
  4734. ufbx_inline ufbx_vec3 ufbxi_lerp3(ufbx_vec3 a, ufbx_vec3 b, ufbx_real t) {
  4735. ufbx_real u = 1.0f - t;
  4736. ufbx_vec3 v = { a.x*u + b.x*t, a.y*u + b.y*t, a.z*u + b.z*t };
  4737. return v;
  4738. }
  4739. ufbx_inline ufbx_real ufbxi_dot3(ufbx_vec3 a, ufbx_vec3 b) {
  4740. return a.x*b.x + a.y*b.y + a.z*b.z;
  4741. }
  4742. ufbx_inline ufbx_real ufbxi_length3(ufbx_vec3 v)
  4743. {
  4744. return (ufbx_real)ufbx_sqrt(v.x*v.x + v.y*v.y + v.z*v.z);
  4745. }
  4746. ufbx_inline ufbx_real ufbxi_min3(ufbx_vec3 v)
  4747. {
  4748. return ufbxi_min_real(ufbxi_min_real(v.x, v.y), v.z);
  4749. }
  4750. ufbx_inline ufbx_vec3 ufbxi_cross3(ufbx_vec3 a, ufbx_vec3 b) {
  4751. ufbx_vec3 v = { a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x };
  4752. return v;
  4753. }
  4754. ufbx_inline ufbx_vec3 ufbxi_normalize3(ufbx_vec3 a) {
  4755. ufbx_real len = (ufbx_real)ufbx_sqrt(ufbxi_dot3(a, a));
  4756. if (len > UFBX_EPSILON) {
  4757. return ufbxi_mul3(a, (ufbx_real)1.0 / len);
  4758. } else {
  4759. ufbx_vec3 zero = { (ufbx_real)0 };
  4760. return zero;
  4761. }
  4762. }
  4763. ufbx_inline ufbx_real ufbxi_distsq2(ufbx_vec2 a, ufbx_vec2 b) {
  4764. ufbx_real dx = a.x - b.x, dy = a.y - b.y;
  4765. return dx*dx + dy*dy;
  4766. }
  4767. static ufbxi_noinline ufbx_vec3 ufbxi_slow_normalize3(const ufbx_vec3 *a) {
  4768. return ufbxi_normalize3(*a);
  4769. }
  4770. static ufbxi_noinline ufbx_vec3 ufbxi_slow_normalized_cross3(const ufbx_vec3 *a, const ufbx_vec3 *b) {
  4771. return ufbxi_normalize3(ufbxi_cross3(*a, *b));
  4772. }
  4773. // -- Threading
  4774. typedef struct ufbxi_task ufbxi_task;
  4775. typedef struct ufbxi_thread ufbxi_thread;
  4776. typedef struct ufbxi_thread_pool ufbxi_thread_pool;
  4777. typedef bool ufbxi_task_fn(ufbxi_task *task);
  4778. struct ufbxi_task {
  4779. void *data;
  4780. const char *error;
  4781. };
  4782. typedef struct {
  4783. ufbxi_task task;
  4784. ufbxi_task_fn *fn;
  4785. } ufbxi_task_imp;
  4786. typedef struct {
  4787. uint32_t max_index;
  4788. uint32_t wait_index;
  4789. } ufbxi_task_group;
  4790. struct ufbxi_thread_pool {
  4791. ufbx_thread_opts opts;
  4792. ufbxi_allocator *ator;
  4793. ufbx_error *error;
  4794. void *user_ptr;
  4795. bool enabled;
  4796. bool failed;
  4797. const char *error_desc;
  4798. uint32_t start_index;
  4799. uint32_t execute_index;
  4800. uint32_t wait_index;
  4801. ufbxi_task_group groups[UFBX_THREAD_GROUP_COUNT];
  4802. uint32_t group;
  4803. uint32_t num_tasks;
  4804. ufbxi_task_imp *tasks;
  4805. };
  4806. static void ufbxi_thread_pool_execute(ufbxi_thread_pool *pool, uint32_t index)
  4807. {
  4808. ufbxi_task_imp *imp = &pool->tasks[index % pool->num_tasks];
  4809. if (imp->fn(&imp->task)) {
  4810. imp->task.error = NULL;
  4811. } else if (!imp->task.error) {
  4812. imp->task.error = "";
  4813. }
  4814. }
  4815. ufbxi_noinline static void ufbxi_thread_pool_update_finished(ufbxi_thread_pool *pool, uint32_t max_index)
  4816. {
  4817. while (pool->wait_index < max_index) {
  4818. ufbxi_task_imp *task = &pool->tasks[pool->wait_index % pool->num_tasks];
  4819. if (!pool->failed && task->task.error) {
  4820. pool->failed = true;
  4821. pool->error_desc = task->task.error;
  4822. }
  4823. pool->wait_index += 1;
  4824. }
  4825. }
  4826. ufbxi_nodiscard ufbxi_noinline static int ufbxi_thread_pool_wait_imp(ufbxi_thread_pool *pool, uint32_t group, bool can_fail)
  4827. {
  4828. uint32_t max_index = pool->groups[group].max_index;
  4829. if (pool->groups[group].wait_index < max_index) {
  4830. pool->opts.pool.wait_fn(pool->opts.pool.user, (ufbx_thread_pool_context)pool, group, max_index);
  4831. pool->groups[group].wait_index = max_index;
  4832. }
  4833. ufbxi_thread_pool_update_finished(pool, max_index);
  4834. if (pool->failed && can_fail) {
  4835. ufbx_error *error = pool->error;
  4836. if (pool->error_desc) {
  4837. error->description.data = pool->error_desc;
  4838. error->description.length = strlen(pool->error_desc);
  4839. }
  4840. ufbxi_fail_err(error, "Task failed");
  4841. }
  4842. return 1;
  4843. }
  4844. ufbxi_nodiscard ufbxi_noinline static int ufbxi_thread_pool_wait_group(ufbxi_thread_pool *pool)
  4845. {
  4846. ufbxi_check_err(pool->error, ufbxi_thread_pool_wait_imp(pool, pool->group, true));
  4847. return 1;
  4848. }
  4849. ufbxi_nodiscard ufbxi_noinline static int ufbxi_thread_pool_wait_all(ufbxi_thread_pool *pool)
  4850. {
  4851. for (uint32_t i = 0; i < UFBX_THREAD_GROUP_COUNT; i++) {
  4852. ufbxi_check_err(pool->error, ufbxi_thread_pool_wait_imp(pool, pool->group, true));
  4853. pool->group = (pool->group + 1) % UFBX_THREAD_GROUP_COUNT;
  4854. }
  4855. return 1;
  4856. }
  4857. ufbxi_nodiscard ufbxi_noinline static int ufbxi_thread_pool_init(ufbxi_thread_pool *pool, ufbx_error *error, ufbxi_allocator *ator, const ufbx_thread_opts *opts)
  4858. {
  4859. if (!(opts->pool.run_fn && opts->pool.wait_fn)) return 1;
  4860. pool->enabled = true;
  4861. uint32_t num_tasks = (uint32_t)ufbxi_min_sz(opts->num_tasks, INT32_MAX);
  4862. if (num_tasks == 0) {
  4863. num_tasks = 2048;
  4864. }
  4865. pool->opts = *opts;
  4866. if (pool->opts.pool.init_fn) {
  4867. ufbx_thread_pool_info info; // ufbxi_uninit
  4868. info.max_concurrent_tasks = num_tasks;
  4869. ufbxi_check_err(error, pool->opts.pool.init_fn(pool->opts.pool.user, (ufbx_thread_pool_context)pool, &info));
  4870. }
  4871. pool->ator = ator;
  4872. pool->error = error;
  4873. pool->num_tasks = num_tasks;
  4874. pool->tasks = ufbxi_alloc(ator, ufbxi_task_imp, num_tasks);
  4875. ufbxi_check_err(error, pool->tasks);
  4876. return 1;
  4877. }
  4878. ufbxi_noinline static void ufbxi_thread_pool_free(ufbxi_thread_pool *pool)
  4879. {
  4880. if (!pool->enabled) return;
  4881. // Wait for all pending tasks
  4882. for (uint32_t i = 0; i < UFBX_THREAD_GROUP_COUNT; i++) {
  4883. pool->group = (pool->group + 1) % UFBX_THREAD_GROUP_COUNT;
  4884. ufbxi_ignore(ufbxi_thread_pool_wait_imp(pool, pool->group, false));
  4885. }
  4886. if (pool->opts.pool.free_fn) {
  4887. pool->opts.pool.free_fn(pool->opts.pool.user, (ufbx_thread_pool_context)pool);
  4888. }
  4889. ufbxi_free(pool->ator, ufbxi_task_imp, pool->tasks, pool->num_tasks);
  4890. }
  4891. ufbxi_nodiscard ufbxi_noinline static uint32_t ufbxi_thread_pool_available_tasks(ufbxi_thread_pool *pool)
  4892. {
  4893. return pool->num_tasks - (pool->start_index - pool->wait_index);
  4894. }
  4895. ufbxi_noinline static void ufbxi_thread_pool_flush_group(ufbxi_thread_pool *pool)
  4896. {
  4897. uint32_t group = pool->group;
  4898. uint32_t start_index = pool->execute_index;
  4899. uint32_t count = pool->start_index - start_index;
  4900. if (count > 0) {
  4901. if (pool->opts.pool.run_fn) {
  4902. pool->opts.pool.run_fn(pool->opts.pool.user, (ufbx_thread_pool_context)pool, group, start_index, count);
  4903. }
  4904. pool->groups[group].max_index = start_index + count;
  4905. pool->execute_index = start_index + count;
  4906. }
  4907. pool->group = (group + 1) % UFBX_THREAD_GROUP_COUNT;
  4908. }
  4909. ufbxi_nodiscard ufbxi_noinline static ufbxi_task *ufbxi_thread_pool_create_task(ufbxi_thread_pool *pool, ufbxi_task_fn *fn)
  4910. {
  4911. uint32_t index = pool->start_index;
  4912. if (index - pool->wait_index >= pool->num_tasks) {
  4913. if (index - pool->wait_index >= pool->num_tasks) {
  4914. // No space left
  4915. return NULL;
  4916. }
  4917. } else if (index == INT32_MAX) {
  4918. // TODO: Expand to 64 bits if possible?
  4919. return NULL;
  4920. }
  4921. ufbxi_task_imp *imp = &pool->tasks[index % pool->num_tasks];
  4922. if (index < pool->num_tasks) {
  4923. memset(imp, 0, sizeof(ufbxi_task_imp));
  4924. }
  4925. imp->fn = fn;
  4926. return &imp->task;
  4927. }
  4928. static void ufbxi_thread_pool_run_task(ufbxi_thread_pool *pool, ufbxi_task *task)
  4929. {
  4930. (void)task;
  4931. uint32_t index = pool->start_index;
  4932. ufbx_assert(task == &pool->tasks[index % pool->num_tasks].task);
  4933. pool->start_index = index + 1;
  4934. }
  4935. // -- Type definitions
  4936. typedef struct ufbxi_node ufbxi_node;
  4937. typedef enum {
  4938. UFBXI_VALUE_NONE,
  4939. UFBXI_VALUE_NUMBER,
  4940. UFBXI_VALUE_STRING,
  4941. UFBXI_VALUE_ARRAY,
  4942. } ufbxi_value_type;
  4943. typedef union {
  4944. struct { double f; int64_t i; }; // < if `UFBXI_PROP_NUMBER`
  4945. ufbxi_sanitized_string s; // < if `UFBXI_PROP_STRING`
  4946. } ufbxi_value;
  4947. typedef struct {
  4948. void *data; // < Pointer to `size` bool/int32_t/int64_t/float/double elements
  4949. size_t size; // < Number of elements
  4950. char type; // < FBX type code: b/i/l/f/d
  4951. } ufbxi_value_array;
  4952. struct ufbxi_node {
  4953. const char *name; // < Name of the node (pooled, compare with == to ufbxi_* strings)
  4954. uint32_t num_children; // < Number of child nodes
  4955. uint8_t name_len; // < Length of `name` in bytes
  4956. // If `value_type_mask == UFBXI_PROP_ARRAY` then the node is an array
  4957. // (`array` field is valid) otherwise the node has N values in `vals`
  4958. // where the type of each value is stored in 2 bits per value from LSB.
  4959. // ie. `vals[ix]` type is `(value_type_mask >> (ix*2)) & 0x3`
  4960. uint16_t value_type_mask;
  4961. ufbxi_node *children;
  4962. union {
  4963. ufbxi_value_array *array; // if `prop_type_mask == UFBXI_PROP_ARRAY`
  4964. ufbxi_value *vals; // otherwise
  4965. };
  4966. };
  4967. typedef struct ufbxi_refcount ufbxi_refcount;
  4968. struct ufbxi_refcount {
  4969. ufbxi_refcount *parent;
  4970. void *align_0;
  4971. uint32_t self_magic;
  4972. uint32_t type_magic;
  4973. ufbxi_buf buf;
  4974. ufbxi_allocator ator;
  4975. uint64_t zero_pad_pre[8];
  4976. ufbxi_atomic_counter refcount;
  4977. uint64_t zero_pad_post[8];
  4978. };
  4979. static ufbxi_noinline void ufbxi_init_ref(ufbxi_refcount *refcount, uint32_t magic, ufbxi_refcount *parent);
  4980. static ufbxi_noinline void ufbxi_retain_ref(ufbxi_refcount *refcount);
  4981. #define ufbxi_get_imp(type, ptr) ((type*)((char*)ptr - sizeof(ufbxi_refcount)))
  4982. typedef struct {
  4983. ufbxi_refcount refcount;
  4984. ufbx_scene scene;
  4985. uint32_t magic;
  4986. ufbxi_buf string_buf;
  4987. } ufbxi_scene_imp;
  4988. ufbx_static_assert(scene_imp_offset, offsetof(ufbxi_scene_imp, scene) == sizeof(ufbxi_refcount));
  4989. typedef struct {
  4990. ufbxi_refcount refcount;
  4991. ufbx_mesh mesh;
  4992. uint32_t magic;
  4993. } ufbxi_mesh_imp;
  4994. ufbx_static_assert(mesh_imp_offset, offsetof(ufbxi_mesh_imp, mesh) == sizeof(ufbxi_refcount));
  4995. typedef struct {
  4996. // Semantic string data and length eg. for a string token
  4997. // this string doesn't include the quotes.
  4998. char *str_data;
  4999. size_t str_len;
  5000. size_t str_cap;
  5001. // Type of the token, either single character such as '{' or ':'
  5002. // or one of UFBXI_ASCII_* defines.
  5003. char type;
  5004. // Sign for integer if negative.
  5005. bool negative;
  5006. // Parsed semantic value
  5007. union {
  5008. double f64;
  5009. int64_t i64;
  5010. size_t name_len;
  5011. } value;
  5012. } ufbxi_ascii_token;
  5013. typedef struct {
  5014. size_t max_token_length;
  5015. const char *src;
  5016. const char *src_yield;
  5017. const char *src_end;
  5018. bool read_first_comment;
  5019. bool found_version;
  5020. bool parse_as_f32;
  5021. bool src_is_retained;
  5022. ufbxi_buf *retain_buf;
  5023. ufbxi_buf *src_buf;
  5024. ufbxi_ascii_token prev_token;
  5025. ufbxi_ascii_token token;
  5026. } ufbxi_ascii;
  5027. typedef struct {
  5028. const char *type;
  5029. ufbx_string sub_type;
  5030. ufbx_props props;
  5031. } ufbxi_template;
  5032. typedef struct {
  5033. uint64_t fbx_id;
  5034. uint32_t element_id;
  5035. uint32_t user_id;
  5036. } ufbxi_fbx_id_entry;
  5037. typedef struct {
  5038. uint64_t node_fbx_id;
  5039. uint64_t attr_fbx_id;
  5040. } ufbxi_fbx_attr_entry;
  5041. // Temporary connection before we resolve the element pointers
  5042. typedef struct {
  5043. uint64_t src, dst;
  5044. ufbx_string src_prop;
  5045. ufbx_string dst_prop;
  5046. } ufbxi_tmp_connection;
  5047. typedef struct {
  5048. uint64_t fbx_id;
  5049. ufbx_string name;
  5050. ufbx_props props;
  5051. ufbx_dom_node *dom_node;
  5052. } ufbxi_element_info;
  5053. typedef struct {
  5054. uint64_t bone_fbx_id;
  5055. ufbx_matrix bone_to_world;
  5056. } ufbxi_tmp_bone_pose;
  5057. typedef struct {
  5058. ufbx_string prop_name;
  5059. uint32_t *face_texture;
  5060. size_t num_faces;
  5061. bool all_same;
  5062. } ufbxi_tmp_mesh_texture;
  5063. typedef struct {
  5064. ufbxi_tmp_mesh_texture *texture_arr;
  5065. size_t texture_count;
  5066. } ufbxi_mesh_extra;
  5067. typedef struct {
  5068. int32_t material_id;
  5069. int32_t texture_id;
  5070. ufbx_string prop_name;
  5071. } ufbxi_tmp_material_texture;
  5072. typedef struct {
  5073. int32_t *blend_modes;
  5074. size_t num_blend_modes;
  5075. ufbx_real *alphas;
  5076. size_t num_alphas;
  5077. } ufbxi_texture_extra;
  5078. typedef enum {
  5079. UFBXI_OBJ_ATTRIB_POSITION,
  5080. UFBXI_OBJ_ATTRIB_UV,
  5081. UFBXI_OBJ_ATTRIB_NORMAL,
  5082. UFBXI_OBJ_ATTRIB_COLOR,
  5083. } ufbxi_obj_attrib;
  5084. #define UFBXI_OBJ_NUM_ATTRIBS 3
  5085. #define UFBXI_OBJ_NUM_ATTRIBS_EXT 4
  5086. typedef struct {
  5087. uint64_t min_ix, max_ix;
  5088. } ufbxi_obj_index_range;
  5089. typedef struct {
  5090. size_t num_faces;
  5091. size_t num_indices;
  5092. ufbxi_obj_index_range vertex_range[UFBXI_OBJ_NUM_ATTRIBS];
  5093. ufbx_node *fbx_node;
  5094. ufbx_mesh *fbx_mesh;
  5095. uint64_t fbx_node_id;
  5096. uint64_t fbx_mesh_id;
  5097. uint32_t usemtl_base;
  5098. uint32_t num_groups;
  5099. } ufbxi_obj_mesh;
  5100. typedef struct {
  5101. const char *name;
  5102. uint32_t local_id;
  5103. uint32_t mesh_id;
  5104. } ufbxi_obj_group_entry;
  5105. typedef struct {
  5106. uint64_t *indices;
  5107. size_t num_left;
  5108. } ufbxi_obj_fast_indices;
  5109. // Temporary pointer to a `ufbx_anim_stack` by name used to patch start/stop
  5110. // time from "Takes" if necessary.
  5111. typedef struct {
  5112. const char *name;
  5113. ufbx_anim_stack *stack;
  5114. } ufbxi_tmp_anim_stack;
  5115. typedef struct {
  5116. ufbx_string absolute_filename;
  5117. ufbx_blob content;
  5118. } ufbxi_file_content;
  5119. typedef struct {
  5120. // Current line and tokens.
  5121. // NOTE: `line` and `tokens` are not NULL-terminated nor UTF-8!
  5122. // `line` is guaranteed to be terminated by a `\n`
  5123. ufbx_string line;
  5124. ufbx_string *tokens;
  5125. size_t tokens_cap;
  5126. size_t num_tokens;
  5127. ufbxi_obj_fast_indices fast_indices[UFBXI_OBJ_NUM_ATTRIBS];
  5128. size_t vertex_count[UFBXI_OBJ_NUM_ATTRIBS_EXT];
  5129. ufbxi_buf tmp_vertices[UFBXI_OBJ_NUM_ATTRIBS_EXT];
  5130. ufbxi_buf tmp_indices[UFBXI_OBJ_NUM_ATTRIBS_EXT];
  5131. ufbxi_buf tmp_color_valid;
  5132. ufbxi_buf tmp_faces;
  5133. ufbxi_buf tmp_face_smoothing;
  5134. ufbxi_buf tmp_face_group;
  5135. ufbxi_buf tmp_face_group_infos;
  5136. ufbxi_buf tmp_face_material;
  5137. ufbxi_buf tmp_meshes;
  5138. ufbxi_buf tmp_props;
  5139. ufbxi_map group_map;
  5140. size_t read_progress;
  5141. ufbxi_obj_mesh *mesh;
  5142. uint64_t usemtl_fbx_id;
  5143. uint32_t usemtl_index;
  5144. ufbx_string usemtl_name;
  5145. uint32_t face_material;
  5146. uint32_t face_group;
  5147. bool has_face_group;
  5148. bool face_smoothing;
  5149. bool has_face_smoothing;
  5150. bool has_vertex_color;
  5151. size_t mrgb_vertex_count;
  5152. bool eof;
  5153. bool initialized;
  5154. ufbx_blob mtllib_relative_path;
  5155. ufbx_material **tmp_materials;
  5156. size_t tmp_materials_cap;
  5157. ufbx_string object;
  5158. ufbx_string group;
  5159. bool material_dirty;
  5160. bool object_dirty;
  5161. bool group_dirty;
  5162. bool face_group_dirty;
  5163. } ufbxi_obj_context;
  5164. typedef struct {
  5165. ufbx_error error;
  5166. uint32_t version;
  5167. ufbx_exporter exporter;
  5168. uint32_t exporter_version;
  5169. bool from_ascii;
  5170. bool local_big_endian;
  5171. bool file_big_endian;
  5172. bool sure_fbx;
  5173. bool retain_mesh_parts;
  5174. bool read_legacy_settings;
  5175. uint32_t double_parse_flags;
  5176. ufbx_load_opts opts;
  5177. // IO
  5178. uint64_t data_offset;
  5179. ufbx_read_fn *read_fn;
  5180. ufbx_skip_fn *skip_fn;
  5181. ufbx_close_fn *close_fn;
  5182. void *read_user;
  5183. char *read_buffer;
  5184. size_t read_buffer_size;
  5185. const char *data_begin;
  5186. const char *data;
  5187. size_t yield_size;
  5188. size_t data_size;
  5189. // Allocators
  5190. ufbxi_allocator ator_result;
  5191. ufbxi_allocator ator_tmp;
  5192. // Temporary maps
  5193. ufbxi_map prop_type_map; // < `ufbxi_prop_type_name` Property type to enum
  5194. ufbxi_map fbx_id_map; // < `ufbxi_fbx_id_entry` FBX ID to local ID
  5195. ufbxi_map texture_file_map; // < `ufbxi_texture_file_entry` absolute raw filename to element ID
  5196. ufbxi_map anim_stack_map; // < `ufbxi_tmp_anim_stack` anim stacks by name before finalization
  5197. // 6x00 specific maps
  5198. ufbxi_map fbx_attr_map; // < `ufbxi_fbx_attr_entry` Node ID to attrib ID
  5199. ufbxi_map node_prop_set; // < `const char*` Node property names
  5200. // DOM nodes
  5201. ufbxi_map dom_node_map; // < `const char*` Node property names
  5202. // Temporary array
  5203. char *tmp_arr;
  5204. size_t tmp_arr_size;
  5205. char *swap_arr;
  5206. size_t swap_arr_size;
  5207. // Generated index buffers
  5208. size_t max_zero_indices;
  5209. size_t max_consecutive_indices;
  5210. // Temporary buffers
  5211. ufbxi_buf tmp;
  5212. ufbxi_buf tmp_parse;
  5213. ufbxi_buf tmp_stack;
  5214. ufbxi_buf tmp_connections;
  5215. ufbxi_buf tmp_node_ids;
  5216. ufbxi_buf tmp_elements;
  5217. ufbxi_buf tmp_element_offsets;
  5218. ufbxi_buf tmp_element_fbx_ids;
  5219. ufbxi_buf tmp_element_ptrs;
  5220. ufbxi_buf tmp_typed_element_offsets[UFBX_ELEMENT_TYPE_COUNT];
  5221. ufbxi_buf tmp_mesh_textures;
  5222. ufbxi_buf tmp_full_weights;
  5223. ufbxi_buf tmp_dom_nodes;
  5224. ufbxi_buf tmp_element_id;
  5225. ufbxi_buf tmp_ascii_spans;
  5226. ufbxi_buf tmp_thread_parse[UFBX_THREAD_GROUP_COUNT];
  5227. size_t tmp_element_byte_offset;
  5228. ufbxi_template *templates;
  5229. size_t num_templates;
  5230. ufbx_dom_node *dom_parse_toplevel;
  5231. size_t dom_parse_num_children;
  5232. uint32_t *p_element_id;
  5233. // String pool
  5234. ufbxi_string_pool string_pool;
  5235. // Result buffers, these are retained in `ufbx_scene` returned to user.
  5236. ufbxi_buf result;
  5237. // Top-level state
  5238. ufbxi_node *top_nodes;
  5239. size_t top_nodes_len, top_nodes_cap;
  5240. bool parsed_to_end;
  5241. // "Focused" top-level node and child index, if `top_child_index == SIZE_MAX`
  5242. // the children are parsed on demand.
  5243. ufbxi_node *top_node;
  5244. size_t top_child_index;
  5245. ufbxi_node top_child;
  5246. bool has_next_child;
  5247. // Shared consecutive and all-zero index buffers
  5248. uint32_t *zero_indices;
  5249. uint32_t *consecutive_indices;
  5250. // Call progress function periodically
  5251. ptrdiff_t progress_timer;
  5252. uint64_t progress_bytes_total;
  5253. uint64_t latest_progress_bytes;
  5254. size_t progress_interval;
  5255. // Extra data on the side of elements
  5256. void **element_extra_arr;
  5257. size_t element_extra_cap;
  5258. // Temporary per-element flags
  5259. uint8_t *tmp_element_flag;
  5260. ufbxi_ascii ascii;
  5261. bool has_geometry_transform_nodes;
  5262. bool has_scale_helper_nodes;
  5263. bool retain_vertex_w;
  5264. ufbx_mirror_axis mirror_axis;
  5265. ufbxi_node root;
  5266. ufbx_scene scene;
  5267. ufbxi_scene_imp *scene_imp;
  5268. ufbx_inflate_retain *inflate_retain;
  5269. // Per-mesh consecutive indices used by `ufbxi_flip_winding()`.
  5270. uint32_t *tmp_mesh_consecutive_indices;
  5271. uint64_t root_id;
  5272. uint32_t num_elements;
  5273. ufbxi_node legacy_node;
  5274. uint64_t legacy_implicit_anim_layer_id;
  5275. ufbxi_file_content *file_content;
  5276. size_t num_file_content;
  5277. int64_t ktime_sec;
  5278. double ktime_sec_double;
  5279. bool eof;
  5280. ufbxi_obj_context obj;
  5281. ufbx_matrix axis_matrix;
  5282. ufbx_real unit_scale;
  5283. ufbxi_warnings warnings;
  5284. bool deferred_failure;
  5285. bool parse_threaded;
  5286. ufbxi_thread_pool thread_pool;
  5287. } ufbxi_context;
  5288. static ufbxi_noinline int ufbxi_fail_imp(ufbxi_context *uc, const char *cond, const char *func, uint32_t line)
  5289. {
  5290. return ufbxi_fail_imp_err(&uc->error, cond, func, line);
  5291. }
  5292. #define ufbxi_check(cond) if (ufbxi_unlikely(!ufbxi_trace(cond))) return ufbxi_fail_imp(uc, ufbxi_cond_str(cond), ufbxi_function, ufbxi_line)
  5293. #define ufbxi_check_return(cond, ret) do { if (ufbxi_unlikely(!ufbxi_trace(cond))) { ufbxi_fail_imp(uc, ufbxi_cond_str(cond), ufbxi_function, ufbxi_line); return ret; } } while (0)
  5294. #define ufbxi_fail(desc) return ufbxi_fail_imp(uc, desc, ufbxi_function, ufbxi_line)
  5295. #define ufbxi_fail_return(desc, ret) do { ufbxi_fail_imp(uc, desc, ufbxi_function, ufbxi_line); return ret; } while (0)
  5296. #define ufbxi_check_msg(cond, msg) if (ufbxi_unlikely(!ufbxi_trace(cond))) return ufbxi_fail_imp(uc, ufbxi_error_msg(ufbxi_cond_str(cond), msg), ufbxi_function, ufbxi_line)
  5297. #define ufbxi_check_return_msg(cond, ret, msg) do { if (ufbxi_unlikely(!ufbxi_trace(cond))) { ufbxi_fail_imp(uc, ufbxi_error_msg(ufbxi_cond_str(cond), msg), ufbxi_function, ufbxi_line); return ret; } } while (0)
  5298. #define ufbxi_fail_msg(desc, msg) return ufbxi_fail_imp(uc, ufbxi_error_msg(desc, msg), ufbxi_function, ufbxi_line)
  5299. #define ufbxi_warnf(type, ...) ufbxi_warnf_imp(&uc->warnings, type, ~0u, __VA_ARGS__)
  5300. #define ufbxi_warnf_tag(type, element_id, ...) ufbxi_warnf_imp(&uc->warnings, type, (element_id), __VA_ARGS__)
  5301. // -- Progress
  5302. static ufbxi_forceinline uint64_t ufbxi_get_read_offset(ufbxi_context *uc)
  5303. {
  5304. return uc->data_offset + ufbxi_to_size(uc->data - uc->data_begin);
  5305. }
  5306. ufbxi_nodiscard static ufbxi_noinline int ufbxi_report_progress(ufbxi_context *uc)
  5307. {
  5308. if (!uc->opts.progress_cb.fn) return 1;
  5309. uint64_t read_offset = ufbxi_get_read_offset(uc);
  5310. uc->latest_progress_bytes = read_offset;
  5311. ufbx_progress progress = { 0 };
  5312. progress.bytes_read = read_offset;
  5313. progress.bytes_total = uc->progress_bytes_total;
  5314. if (progress.bytes_total < progress.bytes_read) {
  5315. progress.bytes_total = progress.bytes_read;
  5316. }
  5317. uc->progress_timer = 1024;
  5318. uint32_t result = (uint32_t)uc->opts.progress_cb.fn(uc->opts.progress_cb.user, &progress);
  5319. ufbx_assert(result == UFBX_PROGRESS_CONTINUE || result == UFBX_PROGRESS_CANCEL);
  5320. ufbxi_check_msg(result != UFBX_PROGRESS_CANCEL, "Cancelled");
  5321. return 1;
  5322. }
  5323. // TODO: Remove `ufbxi_unused` when it's not needed anymore
  5324. ufbxi_unused ufbxi_nodiscard static ufbxi_forceinline int ufbxi_progress(ufbxi_context *uc, size_t work_units)
  5325. {
  5326. if (!uc->opts.progress_cb.fn) return 1;
  5327. ptrdiff_t left = uc->progress_timer - (ptrdiff_t)work_units;
  5328. uc->progress_timer = left;
  5329. if (left > 0) return 1;
  5330. return ufbxi_report_progress(uc);
  5331. }
  5332. // -- IO
  5333. static ufbxi_noinline const char *ufbxi_refill(ufbxi_context *uc, size_t size, bool require_size)
  5334. {
  5335. ufbx_assert(uc->data_size < size);
  5336. ufbxi_check_return(!uc->eof, NULL);
  5337. if (require_size) {
  5338. ufbxi_check_return_msg(uc->read_fn || uc->data_size > 0, NULL, "Empty file");
  5339. ufbxi_check_return_msg(uc->read_fn, NULL, "Truncated file");
  5340. } else if (!uc->read_fn) {
  5341. uc->eof = true;
  5342. return uc->data;
  5343. }
  5344. void *data_to_free = NULL;
  5345. size_t size_to_free = 0;
  5346. // Grow the read buffer if necessary, data is copied over below with the
  5347. // usual path so the free is deferred (`size_to_free`, `data_to_free`)
  5348. if (size > uc->read_buffer_size) {
  5349. size_t new_size = ufbxi_max_sz(size, uc->opts.read_buffer_size);
  5350. new_size = ufbxi_max_sz(new_size, uc->read_buffer_size * 2);
  5351. size_to_free = uc->read_buffer_size;
  5352. data_to_free = uc->read_buffer;
  5353. char *new_buffer = ufbxi_alloc(&uc->ator_tmp, char, new_size);
  5354. ufbxi_check_return(new_buffer, NULL);
  5355. uc->read_buffer = new_buffer;
  5356. uc->read_buffer_size = new_size;
  5357. }
  5358. // Copy the remains of the previous buffer to the beginning of the new one
  5359. size_t data_size = uc->data_size;
  5360. if (data_size > 0) {
  5361. ufbx_assert(uc->read_buffer != NULL && uc->data != NULL);
  5362. memmove(uc->read_buffer, uc->data, data_size);
  5363. }
  5364. if (size_to_free) {
  5365. ufbxi_free(&uc->ator_tmp, char, data_to_free, size_to_free);
  5366. }
  5367. // Fill the rest of the buffer with user data
  5368. size_t data_capacity = uc->read_buffer_size;
  5369. while (data_size < data_capacity) {
  5370. size_t to_read = data_capacity - data_size;
  5371. size_t read_result = uc->read_fn(uc->read_user, uc->read_buffer + data_size, to_read);
  5372. ufbxi_check_return_msg(read_result != SIZE_MAX, NULL, "IO error");
  5373. ufbxi_check_return(read_result <= to_read, NULL);
  5374. data_size += read_result;
  5375. if (read_result == 0) {
  5376. uc->eof = true;
  5377. break;
  5378. }
  5379. }
  5380. if (require_size) {
  5381. if (uc->data_offset == 0) {
  5382. ufbxi_check_return_msg(data_size > 0, NULL, "Empty file");
  5383. }
  5384. ufbxi_check_return_msg(data_size >= size, NULL, "Truncated file");
  5385. }
  5386. uc->data_offset += ufbxi_to_size(uc->data - uc->data_begin);
  5387. uc->data_begin = uc->data = uc->read_buffer;
  5388. uc->data_size = data_size;
  5389. return uc->read_buffer;
  5390. }
  5391. static ufbxi_forceinline void ufbxi_pause_progress(ufbxi_context *uc)
  5392. {
  5393. uc->data_size += uc->yield_size;
  5394. uc->yield_size = 0;
  5395. }
  5396. static ufbxi_noinline int ufbxi_resume_progress(ufbxi_context *uc)
  5397. {
  5398. uc->yield_size = ufbxi_min_sz(uc->data_size, uc->progress_interval);
  5399. uc->data_size -= uc->yield_size;
  5400. if (ufbxi_get_read_offset(uc) - uc->latest_progress_bytes >= uc->progress_interval) {
  5401. ufbxi_check(ufbxi_report_progress(uc));
  5402. }
  5403. return 1;
  5404. }
  5405. static ufbxi_noinline const char *ufbxi_yield(ufbxi_context *uc, size_t size)
  5406. {
  5407. const char *ret;
  5408. uc->data_size += uc->yield_size;
  5409. if (uc->data_size >= size) {
  5410. ret = uc->data;
  5411. } else {
  5412. ret = ufbxi_refill(uc, size, true);
  5413. }
  5414. uc->yield_size = ufbxi_min_sz(uc->data_size, ufbxi_max_sz(size, uc->progress_interval));
  5415. uc->data_size -= uc->yield_size;
  5416. ufbxi_check_return(ufbxi_report_progress(uc), NULL);
  5417. return ret;
  5418. }
  5419. static ufbxi_forceinline const char *ufbxi_peek_bytes(ufbxi_context *uc, size_t size)
  5420. {
  5421. if (uc->yield_size >= size) {
  5422. return uc->data;
  5423. } else {
  5424. return ufbxi_yield(uc, size);
  5425. }
  5426. }
  5427. static ufbxi_forceinline const char *ufbxi_read_bytes(ufbxi_context *uc, size_t size)
  5428. {
  5429. // Refill the current buffer if necessary
  5430. const char *ret;
  5431. if (uc->yield_size >= size) {
  5432. ret = uc->data;
  5433. } else {
  5434. ret = ufbxi_yield(uc, size);
  5435. if (!ret) return NULL;
  5436. }
  5437. // Advance the read position inside the current buffer
  5438. uc->yield_size -= size;
  5439. uc->data = ret + size;
  5440. return ret;
  5441. }
  5442. static ufbxi_forceinline void ufbxi_consume_bytes(ufbxi_context *uc, size_t size)
  5443. {
  5444. // Bytes must have been checked first with `ufbxi_peek_bytes()`
  5445. ufbx_assert(size <= uc->yield_size);
  5446. uc->yield_size -= size;
  5447. uc->data += size;
  5448. }
  5449. ufbxi_nodiscard static ufbxi_noinline int ufbxi_skip_bytes(ufbxi_context *uc, uint64_t size)
  5450. {
  5451. if (uc->skip_fn) {
  5452. ufbxi_pause_progress(uc);
  5453. if (size > uc->data_size) {
  5454. size -= uc->data_size;
  5455. uc->data += uc->data_size;
  5456. uc->data_size = 0;
  5457. uc->data_offset += size;
  5458. while (size >= UFBXI_MAX_SKIP_SIZE) {
  5459. size -= UFBXI_MAX_SKIP_SIZE;
  5460. ufbxi_check_msg(uc->skip_fn(uc->read_user, UFBXI_MAX_SKIP_SIZE - 1), "Truncated file");
  5461. // Check that we can read at least one byte in case the file is broken
  5462. // and causes us to seek indefinitely forwards as `fseek()` does not
  5463. // report if we hit EOF...
  5464. char single_byte[1]; // ufbxi_uninit
  5465. size_t num_read = uc->read_fn(uc->read_user, single_byte, 1);
  5466. ufbxi_check_msg(num_read <= 1, "IO error");
  5467. ufbxi_check_msg(num_read == 1, "Truncated file");
  5468. }
  5469. if (size > 0) {
  5470. ufbxi_check_msg(uc->skip_fn(uc->read_user, (size_t)size), "Truncated file");
  5471. }
  5472. } else {
  5473. uc->data += (size_t)size;
  5474. uc->data_size -= (size_t)size;
  5475. }
  5476. ufbxi_check(ufbxi_resume_progress(uc));
  5477. } else {
  5478. // Read and discard bytes in reasonable chunks
  5479. uint64_t skip_size = ufbxi_max64(uc->read_buffer_size, uc->opts.read_buffer_size);
  5480. while (size > 0) {
  5481. uint64_t to_skip = ufbxi_min64(size, skip_size);
  5482. ufbxi_check(ufbxi_read_bytes(uc, (size_t)to_skip));
  5483. size -= to_skip;
  5484. }
  5485. }
  5486. return 1;
  5487. }
  5488. ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_to(ufbxi_context *uc, void *dst, size_t size)
  5489. {
  5490. char *ptr = (char*)dst;
  5491. ufbxi_pause_progress(uc);
  5492. // Copy data from the current buffer first
  5493. size_t len = ufbxi_min_sz(uc->data_size, size);
  5494. memcpy(ptr, uc->data, len);
  5495. uc->data += len;
  5496. uc->data_size -= len;
  5497. ptr += len;
  5498. size -= len;
  5499. // If there's data left to copy try to read from user IO
  5500. if (size > 0) {
  5501. uc->data_offset += ufbxi_to_size(uc->data - uc->data_begin);
  5502. uc->data_begin = uc->data = NULL;
  5503. uc->data_size = 0;
  5504. ufbxi_check(uc->read_fn);
  5505. while (size > 0) {
  5506. size_t read_result = uc->read_fn(uc->read_user, ptr, size);
  5507. ufbxi_check_msg(read_result != SIZE_MAX, "IO error");
  5508. ufbxi_check(read_result != 0);
  5509. ptr += read_result;
  5510. size -= read_result;
  5511. uc->data_offset += read_result;
  5512. }
  5513. }
  5514. ufbxi_check(ufbxi_resume_progress(uc));
  5515. return 1;
  5516. }
  5517. // -- File IO
  5518. static ufbxi_noinline void ufbxi_init_ator(ufbx_error *error, ufbxi_allocator *ator, const ufbx_allocator_opts *opts, const char *name)
  5519. {
  5520. ufbx_allocator_opts zero_opts;
  5521. if (!opts) {
  5522. memset(&zero_opts, 0, sizeof(zero_opts));
  5523. opts = &zero_opts;
  5524. }
  5525. // `opts` is either passed in or `zero_opts`.
  5526. // cppcheck-suppress uninitvar
  5527. ator->ator = *opts;
  5528. ator->error = error;
  5529. ator->max_size = opts->memory_limit ? opts->memory_limit : SIZE_MAX;
  5530. ator->max_allocs = opts->allocation_limit ? opts->allocation_limit : SIZE_MAX;
  5531. ator->huge_size = opts->huge_threshold ? opts->huge_threshold : 0x100000;
  5532. ator->chunk_max = opts->max_chunk_size ? opts->max_chunk_size : 0x1000000;
  5533. ator->name = name;
  5534. }
  5535. static ufbxi_noinline FILE *ufbxi_fopen(const char *path, size_t path_len, ufbxi_allocator *tmp_ator)
  5536. {
  5537. #if !defined(UFBX_STANDARD_C) && defined(_WIN32)
  5538. wchar_t wpath_buf[256];
  5539. wchar_t *wpath = NULL;
  5540. if (path_len == SIZE_MAX) {
  5541. path_len = strlen(path);
  5542. }
  5543. if (path_len < ufbxi_arraycount(wpath_buf) - 1) {
  5544. wpath = wpath_buf;
  5545. } else {
  5546. wpath = ufbxi_alloc(tmp_ator, wchar_t, path_len + 1);
  5547. if (!wpath) return NULL;
  5548. }
  5549. // Convert UTF-8 to UTF-16 but allow stray surrogate pairs as the Windows
  5550. // file system encoding allows them as well..
  5551. size_t wlen = 0;
  5552. for (size_t i = 0; i < path_len; ) {
  5553. uint32_t code = UINT32_MAX;
  5554. char c = path[i++];
  5555. if ((c & 0x80) == 0) {
  5556. code = (uint32_t)c;
  5557. } else if ((c & 0xe0) == 0xc0) {
  5558. code = (uint32_t)(c & 0x1f);
  5559. if (i < path_len) code = code << 6 | (uint32_t)(path[i++] & 0x3f);
  5560. } else if ((c & 0xf0) == 0xe0) {
  5561. code = (uint32_t)(c & 0x0f);
  5562. if (i < path_len) code = code << 6 | (uint32_t)(path[i++] & 0x3f);
  5563. if (i < path_len) code = code << 6 | (uint32_t)(path[i++] & 0x3f);
  5564. } else if ((c & 0xf8) == 0xf0) {
  5565. code = (uint32_t)(c & 0x07);
  5566. if (i < path_len) code = code << 6 | (uint32_t)(path[i++] & 0x3f);
  5567. if (i < path_len) code = code << 6 | (uint32_t)(path[i++] & 0x3f);
  5568. if (i < path_len) code = code << 6 | (uint32_t)(path[i++] & 0x3f);
  5569. }
  5570. if (code < 0x10000) {
  5571. wpath[wlen++] = (wchar_t)code;
  5572. } else {
  5573. code -= 0x10000;
  5574. wpath[wlen++] = (wchar_t)(0xd800 + (code >> 10));
  5575. wpath[wlen++] = (wchar_t)(0xdc00 + (code & 0x3ff));
  5576. }
  5577. }
  5578. wpath[wlen] = 0;
  5579. FILE *file = NULL;
  5580. #if UFBXI_MSC_VER >= 1400
  5581. if (_wfopen_s(&file, wpath, L"rb") != 0) {
  5582. file = NULL;
  5583. }
  5584. #else
  5585. file = _wfopen(wpath, L"rb");
  5586. #endif
  5587. if (wpath != wpath_buf) {
  5588. ufbxi_free(tmp_ator, wchar_t, wpath, path_len + 1);
  5589. }
  5590. return file;
  5591. #else
  5592. if (path_len == SIZE_MAX) {
  5593. return fopen(path, "rb");
  5594. }
  5595. char copy_buf[256]; // ufbxi_uninit
  5596. char *copy = NULL;
  5597. if (path_len < ufbxi_arraycount(copy_buf) - 1) {
  5598. copy = copy_buf;
  5599. } else {
  5600. copy = ufbxi_alloc(tmp_ator, char, path_len + 1);
  5601. if (!copy) return NULL;
  5602. }
  5603. memcpy(copy, path, path_len);
  5604. copy[path_len] = '\0';
  5605. FILE *file = fopen(copy, "rb");
  5606. if (copy != copy_buf) {
  5607. ufbxi_free(tmp_ator, char, copy, path_len + 1);
  5608. }
  5609. return file;
  5610. #endif
  5611. }
  5612. static uint64_t ufbxi_ftell(FILE *file)
  5613. {
  5614. #if !defined(UFBX_STANDARD_C) && defined(UFBX_HAS_FTELLO)
  5615. off_t result = ftello(file);
  5616. if (result >= 0) return (uint64_t)result;
  5617. #elif !defined(UFBX_STANDARD_C) && defined(_MSC_VER)
  5618. int64_t result = _ftelli64(file);
  5619. if (result >= 0) return (uint64_t)result;
  5620. #else
  5621. long result = ftell(file);
  5622. if (result >= 0) return (uint64_t)result;
  5623. #endif
  5624. return UINT64_MAX;
  5625. }
  5626. static size_t ufbxi_file_read(void *user, void *data, size_t max_size)
  5627. {
  5628. FILE *file = (FILE*)user;
  5629. if (ferror(file)) return SIZE_MAX;
  5630. return fread(data, 1, max_size, file);
  5631. }
  5632. static bool ufbxi_file_skip(void *user, size_t size)
  5633. {
  5634. FILE *file = (FILE*)user;
  5635. ufbx_assert(size <= UFBXI_MAX_SKIP_SIZE);
  5636. if (fseek(file, (long)size, SEEK_CUR) != 0) return false;
  5637. if (ferror(file)) return false;
  5638. return true;
  5639. }
  5640. static void ufbxi_file_close(void *user)
  5641. {
  5642. FILE *file = (FILE*)user;
  5643. fclose(file);
  5644. }
  5645. typedef struct {
  5646. const void *data;
  5647. size_t size;
  5648. size_t position;
  5649. ufbx_close_memory_cb close_cb;
  5650. // Own allocation information
  5651. size_t self_size;
  5652. ufbxi_allocator ator;
  5653. ufbx_error error;
  5654. char data_copy[];
  5655. } ufbxi_memory_stream;
  5656. static size_t ufbxi_memory_read(void *user, void *data, size_t max_size)
  5657. {
  5658. ufbxi_memory_stream *stream = (ufbxi_memory_stream*)user;
  5659. size_t to_read = ufbxi_min_sz(stream->size - stream->position, max_size);
  5660. memcpy(data, (const char*)stream->data + stream->position, to_read);
  5661. stream->position += to_read;
  5662. return to_read;
  5663. }
  5664. static bool ufbxi_memory_skip(void *user, size_t size)
  5665. {
  5666. ufbxi_memory_stream *stream = (ufbxi_memory_stream*)user;
  5667. if (stream->size - stream->position < size) return false;
  5668. stream->position += size;
  5669. return true;
  5670. }
  5671. static void ufbxi_memory_close(void *user)
  5672. {
  5673. ufbxi_memory_stream *stream = (ufbxi_memory_stream*)user;
  5674. if (stream->close_cb.fn) {
  5675. stream->close_cb.fn(stream->close_cb.user, (void*)stream->data, stream->size);
  5676. }
  5677. ufbxi_allocator ator = stream->ator;
  5678. ufbxi_free(&ator, char, stream, stream->self_size);
  5679. ufbxi_free_ator(&ator);
  5680. }
  5681. // -- XML
  5682. #if UFBXI_FEATURE_XML
  5683. typedef struct ufbxi_xml_tag ufbxi_xml_tag;
  5684. typedef struct ufbxi_xml_attrib ufbxi_xml_attrib;
  5685. typedef struct ufbxi_xml_document ufbxi_xml_document;
  5686. struct ufbxi_xml_attrib {
  5687. ufbx_string name;
  5688. ufbx_string value;
  5689. };
  5690. struct ufbxi_xml_tag {
  5691. ufbx_string name;
  5692. ufbx_string text;
  5693. ufbxi_xml_attrib *attribs;
  5694. size_t num_attribs;
  5695. ufbxi_xml_tag *children;
  5696. size_t num_children;
  5697. };
  5698. struct ufbxi_xml_document {
  5699. ufbxi_xml_tag *root;
  5700. ufbxi_buf buf;
  5701. };
  5702. typedef struct {
  5703. ufbx_error error;
  5704. ufbxi_allocator *ator;
  5705. ufbxi_buf tmp_stack;
  5706. ufbxi_buf result;
  5707. ufbxi_xml_document *doc;
  5708. ufbx_read_fn *read_fn;
  5709. void *read_user;
  5710. char *tok;
  5711. size_t tok_cap;
  5712. size_t tok_len;
  5713. const char *pos, *pos_end;
  5714. char data[4096];
  5715. bool io_error;
  5716. } ufbxi_xml_context;
  5717. enum {
  5718. UFBXI_XML_CTYPE_WHITESPACE = 0x1,
  5719. UFBXI_XML_CTYPE_SINGLE_QUOTE = 0x2,
  5720. UFBXI_XML_CTYPE_DOUBLE_QUOTE = 0x4,
  5721. UFBXI_XML_CTYPE_NAME_END = 0x8,
  5722. UFBXI_XML_CTYPE_TAG_START = 0x10,
  5723. UFBXI_XML_CTYPE_END_OF_FILE = 0x20,
  5724. };
  5725. // Generated by `misc/gen_xml_ctype.py`
  5726. static const uint8_t ufbxi_xml_ctype[256] = {
  5727. 32,0,0,0,0,0,0,0,0,9,9,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  5728. 9,0,12,0,0,0,0,10,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,16,8,8,8,
  5729. };
  5730. static ufbxi_noinline void ufbxi_xml_refill(ufbxi_xml_context *xc)
  5731. {
  5732. size_t num = xc->read_fn(xc->read_user, xc->data, sizeof(xc->data));
  5733. if (num == SIZE_MAX || num < sizeof(xc->data)) xc->io_error = true;
  5734. if (num < sizeof(xc->data)) {
  5735. xc->data[num++] = '\0';
  5736. }
  5737. xc->pos = xc->data;
  5738. xc->pos_end = xc->data + num;
  5739. }
  5740. static ufbxi_forceinline void ufbxi_xml_advance(ufbxi_xml_context *xc)
  5741. {
  5742. if (++xc->pos == xc->pos_end) ufbxi_xml_refill(xc);
  5743. }
  5744. ufbxi_nodiscard static ufbxi_noinline int ufbxi_xml_push_token_char(ufbxi_xml_context *xc, char c)
  5745. {
  5746. if (xc->tok_len == xc->tok_cap || UFBXI_IS_REGRESSION) {
  5747. ufbxi_check_err(&xc->error, ufbxi_grow_array(xc->ator, &xc->tok, &xc->tok_cap, xc->tok_len + 1));
  5748. }
  5749. xc->tok[xc->tok_len++] = c;
  5750. return 1;
  5751. }
  5752. static ufbxi_noinline int ufbxi_xml_accept(ufbxi_xml_context *xc, char ch)
  5753. {
  5754. if (*xc->pos == ch) {
  5755. ufbxi_xml_advance(xc);
  5756. return 1;
  5757. } else {
  5758. return 0;
  5759. }
  5760. }
  5761. static ufbxi_noinline void ufbxi_xml_skip_while(ufbxi_xml_context *xc, uint32_t ctypes)
  5762. {
  5763. while (ufbxi_xml_ctype[(uint8_t)*xc->pos] & ctypes) {
  5764. ufbxi_xml_advance(xc);
  5765. }
  5766. }
  5767. ufbxi_nodiscard static ufbxi_noinline int ufbxi_xml_skip_until_string(ufbxi_xml_context *xc, ufbx_string *dst, const char *suffix)
  5768. {
  5769. xc->tok_len = 0;
  5770. size_t match_len = 0, ix = 0, suffix_len = strlen(suffix);
  5771. char buf[16] = { 0 };
  5772. size_t wrap_mask = sizeof(buf) - 1;
  5773. ufbx_assert(suffix_len < sizeof(buf));
  5774. for (;;) {
  5775. char c = *xc->pos;
  5776. ufbxi_check_err_msg(&xc->error, c != 0, "Truncated file");
  5777. ufbxi_xml_advance(xc);
  5778. if (ix >= suffix_len) {
  5779. ufbxi_check_err(&xc->error, ufbxi_xml_push_token_char(xc, buf[(ix - suffix_len) & wrap_mask]));
  5780. }
  5781. buf[ix++ & wrap_mask] = c;
  5782. for (match_len = 0; match_len < suffix_len; match_len++) {
  5783. if (buf[(ix - suffix_len + match_len) & wrap_mask] != suffix[match_len]) {
  5784. break;
  5785. }
  5786. }
  5787. if (match_len == suffix_len) break;
  5788. }
  5789. ufbxi_check_err(&xc->error, ufbxi_xml_push_token_char(xc, '\0'));
  5790. if (dst) {
  5791. dst->length = xc->tok_len - 1;
  5792. dst->data = ufbxi_push_copy(&xc->result, char, xc->tok_len, xc->tok);
  5793. ufbxi_check_err(&xc->error, dst->data);
  5794. }
  5795. return 1;
  5796. }
  5797. static ufbxi_noinline int ufbxi_xml_read_until(ufbxi_xml_context *xc, ufbx_string *dst, uint32_t ctypes)
  5798. {
  5799. xc->tok_len = 0;
  5800. for (;;) {
  5801. char c = *xc->pos;
  5802. if (c == '&') {
  5803. size_t entity_begin = xc->tok_len;
  5804. for (;;) {
  5805. ufbxi_xml_advance(xc);
  5806. c = *xc->pos;
  5807. ufbxi_check_err(&xc->error, c != '\0');
  5808. if (c == ';') break;
  5809. ufbxi_check_err(&xc->error, ufbxi_xml_push_token_char(xc, c));
  5810. }
  5811. ufbxi_xml_advance(xc);
  5812. ufbxi_check_err(&xc->error, ufbxi_xml_push_token_char(xc, '\0'));
  5813. char *entity = xc->tok + entity_begin;
  5814. xc->tok_len = entity_begin;
  5815. if (entity[0] == '#') {
  5816. unsigned long code = 0;
  5817. if (entity[1] == 'x') {
  5818. code = strtoul(entity + 2, NULL, 16);
  5819. } else {
  5820. code = strtoul(entity + 1, NULL, 10);
  5821. }
  5822. char bytes[5] = { 0 };
  5823. if (code < 0x80) {
  5824. bytes[0] = (char)code;
  5825. } else if (code < 0x800) {
  5826. bytes[0] = (char)(0xc0 | (code>>6));
  5827. bytes[1] = (char)(0x80 | (code & 0x3f));
  5828. } else if (code < 0x10000) {
  5829. bytes[0] = (char)(0xe0 | (code>>12));
  5830. bytes[1] = (char)(0x80 | ((code>>6) & 0x3f));
  5831. bytes[2] = (char)(0x80 | (code & 0x3f));
  5832. } else {
  5833. bytes[0] = (char)(0xf0 | (code>>18));
  5834. bytes[1] = (char)(0x80 | ((code>>12) & 0x3f));
  5835. bytes[2] = (char)(0x80 | ((code>>6) & 0x3f));
  5836. bytes[3] = (char)(0x80 | (code & 0x3f));
  5837. }
  5838. for (char *b = bytes; *b; b++) {
  5839. ufbxi_check_err(&xc->error, ufbxi_xml_push_token_char(xc, *b));
  5840. }
  5841. } else {
  5842. char ch = '\0';
  5843. if (!strcmp(entity, "lt")) ch = '<';
  5844. else if (!strcmp(entity, "quot")) ch = '"';
  5845. else if (!strcmp(entity, "amp")) ch = '&';
  5846. else if (!strcmp(entity, "apos")) ch = '\'';
  5847. else if (!strcmp(entity, "gt")) ch = '>';
  5848. if (ch) {
  5849. ufbxi_check_err(&xc->error, ufbxi_xml_push_token_char(xc, ch));
  5850. }
  5851. }
  5852. } else {
  5853. if ((ufbxi_xml_ctype[(uint8_t)c] & ctypes) != 0) break;
  5854. ufbxi_check_err_msg(&xc->error, c != 0, "Truncated file");
  5855. ufbxi_check_err(&xc->error, ufbxi_xml_push_token_char(xc, c));
  5856. ufbxi_xml_advance(xc);
  5857. }
  5858. }
  5859. ufbxi_check_err(&xc->error, ufbxi_xml_push_token_char(xc, '\0'));
  5860. if (dst) {
  5861. dst->length = xc->tok_len - 1;
  5862. dst->data = ufbxi_push_copy(&xc->result, char, xc->tok_len, xc->tok);
  5863. ufbxi_check_err(&xc->error, dst->data);
  5864. }
  5865. return 1;
  5866. }
  5867. // Recursion limited by check at the start
  5868. static ufbxi_noinline int ufbxi_xml_parse_tag(ufbxi_xml_context *xc, size_t depth, bool *p_closing, const char *opening)
  5869. ufbxi_recursive_function(int, ufbxi_xml_parse_tag, (xc, depth, p_closing, opening), UFBXI_MAX_XML_DEPTH + 1,
  5870. (ufbxi_xml_context *xc, size_t depth, bool *p_closing, const char *opening))
  5871. {
  5872. ufbxi_check_err(&xc->error, depth < UFBXI_MAX_XML_DEPTH);
  5873. if (!ufbxi_xml_accept(xc, '<')) {
  5874. if (*xc->pos == '\0') {
  5875. *p_closing = true;
  5876. } else {
  5877. ufbxi_check_err(&xc->error, ufbxi_xml_read_until(xc, NULL, UFBXI_XML_CTYPE_TAG_START | UFBXI_XML_CTYPE_END_OF_FILE));
  5878. bool has_text = false;
  5879. for (size_t i = 0; i < xc->tok_len; i++) {
  5880. if ((ufbxi_xml_ctype[(uint8_t)xc->tok[i]] & UFBXI_XML_CTYPE_WHITESPACE) == 0) {
  5881. has_text = true;
  5882. break;
  5883. }
  5884. }
  5885. if (has_text) {
  5886. ufbxi_xml_tag *tag = ufbxi_push_zero(&xc->tmp_stack, ufbxi_xml_tag, 1);
  5887. ufbxi_check_err(&xc->error, tag);
  5888. tag->name.data = ufbxi_empty_char;
  5889. tag->text.length = xc->tok_len - 1;
  5890. tag->text.data = ufbxi_push_copy(&xc->result, char, xc->tok_len, xc->tok);
  5891. ufbxi_check_err(&xc->error, tag->text.data);
  5892. }
  5893. }
  5894. return 1;
  5895. }
  5896. if (ufbxi_xml_accept(xc, '/')) {
  5897. ufbxi_check_err(&xc->error, ufbxi_xml_read_until(xc, NULL, UFBXI_XML_CTYPE_NAME_END));
  5898. ufbxi_check_err(&xc->error, opening && !strcmp(xc->tok, opening));
  5899. ufbxi_xml_skip_while(xc, UFBXI_XML_CTYPE_WHITESPACE);
  5900. if (!ufbxi_xml_accept(xc, '>')) return 0;
  5901. *p_closing = true;
  5902. return 1;
  5903. } else if (ufbxi_xml_accept(xc, '!')) {
  5904. if (ufbxi_xml_accept(xc, '[')) {
  5905. for (const char *ch = "CDATA["; *ch; ch++) {
  5906. if (!ufbxi_xml_accept(xc, *ch)) return 0;
  5907. }
  5908. ufbxi_xml_tag *tag = ufbxi_push_zero(&xc->tmp_stack, ufbxi_xml_tag, 1);
  5909. ufbxi_check_err(&xc->error, tag);
  5910. ufbxi_check_err(&xc->error, ufbxi_xml_skip_until_string(xc, &tag->text, "]]>"));
  5911. tag->name.data = ufbxi_empty_char;
  5912. } else if (ufbxi_xml_accept(xc, '-')) {
  5913. if (!ufbxi_xml_accept(xc, '-')) return 0;
  5914. ufbxi_check_err(&xc->error, ufbxi_xml_skip_until_string(xc, NULL, "-->"));
  5915. } else {
  5916. // TODO: !DOCTYPE
  5917. ufbxi_check_err(&xc->error, ufbxi_xml_skip_until_string(xc, NULL, ">"));
  5918. }
  5919. return 1;
  5920. } else if (ufbxi_xml_accept(xc, '?')) {
  5921. ufbxi_check_err(&xc->error, ufbxi_xml_skip_until_string(xc, NULL, "?>"));
  5922. return 1;
  5923. }
  5924. ufbxi_xml_tag *tag = ufbxi_push_zero(&xc->tmp_stack, ufbxi_xml_tag, 1);
  5925. ufbxi_check_err(&xc->error, tag);
  5926. ufbxi_check_err(&xc->error, ufbxi_xml_read_until(xc, &tag->name, UFBXI_XML_CTYPE_NAME_END));
  5927. tag->text.data = ufbxi_empty_char;
  5928. bool has_children = false;
  5929. size_t num_attribs = 0;
  5930. for (;;) {
  5931. ufbxi_xml_skip_while(xc, UFBXI_XML_CTYPE_WHITESPACE);
  5932. if (ufbxi_xml_accept(xc, '/')) {
  5933. if (!ufbxi_xml_accept(xc, '>')) return 0;
  5934. break;
  5935. } else if (ufbxi_xml_accept(xc, '>')) {
  5936. has_children = true;
  5937. break;
  5938. } else {
  5939. ufbxi_xml_attrib *attrib = ufbxi_push_zero(&xc->tmp_stack, ufbxi_xml_attrib, 1);
  5940. ufbxi_check_err(&xc->error, attrib);
  5941. ufbxi_check_err(&xc->error, ufbxi_xml_read_until(xc, &attrib->name, UFBXI_XML_CTYPE_NAME_END));
  5942. ufbxi_xml_skip_while(xc, UFBXI_XML_CTYPE_WHITESPACE);
  5943. if (!ufbxi_xml_accept(xc, '=')) return 0;
  5944. ufbxi_xml_skip_while(xc, UFBXI_XML_CTYPE_WHITESPACE);
  5945. uint32_t quote_ctype = 0;
  5946. if (ufbxi_xml_accept(xc, '"')) {
  5947. quote_ctype = UFBXI_XML_CTYPE_DOUBLE_QUOTE;
  5948. } else if (ufbxi_xml_accept(xc, '\'')) {
  5949. quote_ctype = UFBXI_XML_CTYPE_SINGLE_QUOTE;
  5950. } else {
  5951. ufbxi_fail_err(&xc->error, "Bad attrib value");
  5952. }
  5953. ufbxi_check_err(&xc->error, ufbxi_xml_read_until(xc, &attrib->value, quote_ctype));
  5954. ufbxi_xml_advance(xc);
  5955. num_attribs++;
  5956. }
  5957. }
  5958. tag->num_attribs = num_attribs;
  5959. tag->attribs = ufbxi_push_pop(&xc->result, &xc->tmp_stack, ufbxi_xml_attrib, num_attribs);
  5960. ufbxi_check_err(&xc->error, tag->attribs);
  5961. if (has_children) {
  5962. size_t children_begin = xc->tmp_stack.num_items;
  5963. for (;;) {
  5964. bool closing = false;
  5965. ufbxi_check_err(&xc->error, ufbxi_xml_parse_tag(xc, depth + 1, &closing, tag->name.data));
  5966. if (closing) break;
  5967. }
  5968. tag->num_children = xc->tmp_stack.num_items - children_begin;
  5969. tag->children = ufbxi_push_pop(&xc->result, &xc->tmp_stack, ufbxi_xml_tag, tag->num_children);
  5970. ufbxi_check_err(&xc->error, tag->children);
  5971. }
  5972. return 1;
  5973. }
  5974. static ufbxi_noinline int ufbxi_xml_parse_root(ufbxi_xml_context *xc)
  5975. {
  5976. ufbxi_xml_tag *tag = ufbxi_push_zero(&xc->result, ufbxi_xml_tag, 1);
  5977. ufbxi_check_err(&xc->error, tag);
  5978. tag->name.data = ufbxi_empty_char;
  5979. tag->text.data = ufbxi_empty_char;
  5980. for (;;) {
  5981. bool closing = false;
  5982. ufbxi_check_err(&xc->error, ufbxi_xml_parse_tag(xc, 0, &closing, NULL));
  5983. if (closing) break;
  5984. }
  5985. tag->num_children = xc->tmp_stack.num_items;
  5986. tag->children = ufbxi_push_pop(&xc->result, &xc->tmp_stack, ufbxi_xml_tag, tag->num_children);
  5987. ufbxi_check_err(&xc->error, tag->children);
  5988. xc->doc = ufbxi_push(&xc->result, ufbxi_xml_document, 1);
  5989. ufbxi_check_err(&xc->error, xc->doc);
  5990. xc->doc->root = tag;
  5991. xc->doc->buf = xc->result;
  5992. return 1;
  5993. }
  5994. typedef struct {
  5995. ufbxi_allocator *ator;
  5996. ufbx_read_fn *read_fn;
  5997. void *read_user;
  5998. const char *prefix;
  5999. size_t prefix_length;
  6000. } ufbxi_xml_load_opts;
  6001. static ufbxi_noinline ufbxi_xml_document *ufbxi_load_xml(ufbxi_xml_load_opts *opts, ufbx_error *error)
  6002. {
  6003. ufbxi_xml_context xc = { UFBX_ERROR_NONE };
  6004. xc.ator = opts->ator;
  6005. xc.read_fn = opts->read_fn;
  6006. xc.read_user = opts->read_user;
  6007. xc.tmp_stack.ator = xc.ator;
  6008. xc.result.ator = xc.ator;
  6009. xc.result.unordered = true;
  6010. if (opts->prefix_length > 0) {
  6011. xc.pos = opts->prefix;
  6012. xc.pos_end = opts->prefix + opts->prefix_length;
  6013. } else {
  6014. ufbxi_xml_refill(&xc);
  6015. }
  6016. int ok = ufbxi_xml_parse_root(&xc);
  6017. ufbxi_buf_free(&xc.tmp_stack);
  6018. ufbxi_free(xc.ator, char, xc.tok, xc.tok_cap);
  6019. if (ok) {
  6020. return xc.doc;
  6021. } else {
  6022. ufbxi_buf_free(&xc.result);
  6023. if (error) {
  6024. *error = xc.error;
  6025. }
  6026. return NULL;
  6027. }
  6028. }
  6029. static ufbxi_noinline void ufbxi_free_xml(ufbxi_xml_document *doc)
  6030. {
  6031. ufbxi_buf buf = doc->buf;
  6032. ufbxi_buf_free(&buf);
  6033. }
  6034. static ufbxi_noinline ufbxi_xml_tag *ufbxi_xml_find_child(ufbxi_xml_tag *tag, const char *name)
  6035. {
  6036. ufbxi_for(ufbxi_xml_tag, child, tag->children, tag->num_children) {
  6037. if (!strcmp(child->name.data, name)) {
  6038. return child;
  6039. }
  6040. }
  6041. return NULL;
  6042. }
  6043. static ufbxi_noinline ufbxi_xml_attrib *ufbxi_xml_find_attrib(ufbxi_xml_tag *tag, const char *name)
  6044. {
  6045. ufbxi_for(ufbxi_xml_attrib, attrib, tag->attribs, tag->num_attribs) {
  6046. if (!strcmp(attrib->name.data, name)) {
  6047. return attrib;
  6048. }
  6049. }
  6050. return NULL;
  6051. }
  6052. #endif
  6053. // -- FBX value type information
  6054. static char ufbxi_normalize_array_type(char type, char bool_type) {
  6055. switch (type) {
  6056. case 'r': return sizeof(ufbx_real) == sizeof(float) ? 'f' : 'd';
  6057. case 'b': return bool_type;
  6058. default: return type;
  6059. }
  6060. }
  6061. static ufbxi_noinline size_t ufbxi_array_type_size(char type)
  6062. {
  6063. switch (type) {
  6064. case 'r': return sizeof(ufbx_real);
  6065. case 'b': return sizeof(bool);
  6066. case 'c': return sizeof(uint8_t);
  6067. case 'i': return sizeof(int32_t);
  6068. case 'l': return sizeof(int64_t);
  6069. case 'f': return sizeof(float);
  6070. case 'd': return sizeof(double);
  6071. case 's': return sizeof(ufbx_string);
  6072. case 'S': return sizeof(ufbx_string);
  6073. case 'C': return sizeof(ufbx_string);
  6074. default: return 1;
  6075. }
  6076. }
  6077. // -- Node operations
  6078. static ufbxi_noinline ufbxi_node *ufbxi_find_child(ufbxi_node *node, const char *name)
  6079. {
  6080. ufbxi_for(ufbxi_node, c, node->children, node->num_children) {
  6081. if (c->name == name) return c;
  6082. }
  6083. return NULL;
  6084. }
  6085. // Retrieve values from nodes with type codes:
  6086. // Any: '_' (ignore)
  6087. // NUMBER: 'I' int32_t 'L' int64_t 'F' float 'D' double 'R' ufbxi_real 'B' bool 'Z' size_t
  6088. // STRING: 'S' ufbx_string 'C' const char* (checked) 's' ufbx_string 'c' const char * (unchecked) 'b' ufbx_blob
  6089. ufbxi_nodiscard ufbxi_forceinline static int ufbxi_get_val_at(ufbxi_node *node, size_t ix, char fmt, void *v)
  6090. {
  6091. ufbxi_dev_assert(ix < UFBXI_MAX_NON_ARRAY_VALUES);
  6092. ufbxi_value_type type = (ufbxi_value_type)((node->value_type_mask >> (ix*2)) & 0x3);
  6093. switch (fmt) {
  6094. case '_': return 1;
  6095. case 'I': if (type == UFBXI_VALUE_NUMBER) { *(int32_t*)v = (int32_t)node->vals[ix].i; return 1; } else return 0;
  6096. case 'L': if (type == UFBXI_VALUE_NUMBER) { *(int64_t*)v = (int64_t)node->vals[ix].i; return 1; } else return 0;
  6097. case 'F': if (type == UFBXI_VALUE_NUMBER) { *(float*)v = (float)node->vals[ix].f; return 1; } else return 0;
  6098. case 'D': if (type == UFBXI_VALUE_NUMBER) { *(double*)v = (double)node->vals[ix].f; return 1; } else return 0;
  6099. case 'R': if (type == UFBXI_VALUE_NUMBER) { *(ufbx_real*)v = (ufbx_real)node->vals[ix].f; return 1; } else return 0;
  6100. case 'B': if (type == UFBXI_VALUE_NUMBER) { *(bool*)v = node->vals[ix].i != 0; return 1; } else return 0;
  6101. case 'Z': if (type == UFBXI_VALUE_NUMBER) { if (node->vals[ix].i < 0) return 0; *(size_t*)v = (size_t)node->vals[ix].i; return 1; } else return 0;
  6102. case 'S': if (type == UFBXI_VALUE_STRING) {
  6103. ufbxi_sanitized_string src = node->vals[ix].s;
  6104. ufbx_string *dst = (ufbx_string*)v;
  6105. if (src.utf8_length > 0) {
  6106. if (src.utf8_length == UINT32_MAX) return 0;
  6107. dst->data = src.raw_data + src.raw_length + 1;
  6108. dst->length = src.utf8_length;
  6109. } else {
  6110. dst->data = src.raw_data;
  6111. dst->length = src.raw_length;
  6112. }
  6113. return 1;
  6114. } else return 0;
  6115. case 's': if (type == UFBXI_VALUE_STRING) {
  6116. ufbxi_sanitized_string src = node->vals[ix].s;
  6117. ufbx_string *dst = (ufbx_string*)v;
  6118. dst->data = src.raw_data;
  6119. dst->length = src.raw_length;
  6120. return 1;
  6121. } else return 0;
  6122. case 'C': if (type == UFBXI_VALUE_STRING) {
  6123. ufbxi_sanitized_string src = node->vals[ix].s;
  6124. const char **dst = (const char **)v;
  6125. if (src.utf8_length > 0) {
  6126. if (src.utf8_length == UINT32_MAX) return 0;
  6127. *dst = src.raw_data + src.raw_length + 1;
  6128. } else {
  6129. *dst = src.raw_data;
  6130. }
  6131. return 1;
  6132. } else return 0;
  6133. case 'c': if (type == UFBXI_VALUE_STRING) {
  6134. ufbxi_sanitized_string src = node->vals[ix].s;
  6135. const char **dst = (const char **)v;
  6136. *dst = src.raw_data;
  6137. return 1;
  6138. } else return 0;
  6139. case 'b': if (type == UFBXI_VALUE_STRING) {
  6140. ufbxi_sanitized_string src = node->vals[ix].s;
  6141. ufbx_blob *dst = (ufbx_blob*)v;
  6142. dst->data = src.raw_data;
  6143. dst->size = src.raw_length;
  6144. return 1;
  6145. } else return 0;
  6146. default:
  6147. ufbxi_unreachable("Bad format char");
  6148. return 0;
  6149. }
  6150. }
  6151. ufbxi_nodiscard ufbxi_noinline static ufbxi_value_array *ufbxi_get_array(ufbxi_node *node, char fmt)
  6152. {
  6153. if (node->value_type_mask != UFBXI_VALUE_ARRAY) return NULL;
  6154. ufbxi_value_array *array = node->array;
  6155. if (fmt != '?') {
  6156. fmt = ufbxi_normalize_array_type(fmt, 'b');
  6157. if (array->type != fmt) return NULL;
  6158. }
  6159. return array;
  6160. }
  6161. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_get_val1(ufbxi_node *node, const char *fmt, void *v0)
  6162. {
  6163. if (!ufbxi_get_val_at(node, 0, fmt[0], v0)) return 0;
  6164. return 1;
  6165. }
  6166. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_get_val2(ufbxi_node *node, const char *fmt, void *v0, void *v1)
  6167. {
  6168. if (!ufbxi_get_val_at(node, 0, fmt[0], v0)) return 0;
  6169. if (!ufbxi_get_val_at(node, 1, fmt[1], v1)) return 0;
  6170. return 1;
  6171. }
  6172. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_get_val3(ufbxi_node *node, const char *fmt, void *v0, void *v1, void *v2)
  6173. {
  6174. if (!ufbxi_get_val_at(node, 0, fmt[0], v0)) return 0;
  6175. if (!ufbxi_get_val_at(node, 1, fmt[1], v1)) return 0;
  6176. if (!ufbxi_get_val_at(node, 2, fmt[2], v2)) return 0;
  6177. return 1;
  6178. }
  6179. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_get_val4(ufbxi_node *node, const char *fmt, void *v0, void *v1, void *v2, void *v3)
  6180. {
  6181. if (!ufbxi_get_val_at(node, 0, fmt[0], v0)) return 0;
  6182. if (!ufbxi_get_val_at(node, 1, fmt[1], v1)) return 0;
  6183. if (!ufbxi_get_val_at(node, 2, fmt[2], v2)) return 0;
  6184. if (!ufbxi_get_val_at(node, 3, fmt[3], v3)) return 0;
  6185. return 1;
  6186. }
  6187. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_get_val5(ufbxi_node *node, const char *fmt, void *v0, void *v1, void *v2, void *v3, void *v4)
  6188. {
  6189. if (!ufbxi_get_val_at(node, 0, fmt[0], v0)) return 0;
  6190. if (!ufbxi_get_val_at(node, 1, fmt[1], v1)) return 0;
  6191. if (!ufbxi_get_val_at(node, 2, fmt[2], v2)) return 0;
  6192. if (!ufbxi_get_val_at(node, 3, fmt[3], v3)) return 0;
  6193. if (!ufbxi_get_val_at(node, 4, fmt[4], v4)) return 0;
  6194. return 1;
  6195. }
  6196. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_find_val1(ufbxi_node *node, const char *name, const char *fmt, void *v0)
  6197. {
  6198. ufbxi_node *child = ufbxi_find_child(node, name);
  6199. if (!child) return 0;
  6200. if (!ufbxi_get_val_at(child, 0, fmt[0], v0)) return 0;
  6201. return 1;
  6202. }
  6203. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_find_val2(ufbxi_node *node, const char *name, const char *fmt, void *v0, void *v1)
  6204. {
  6205. ufbxi_node *child = ufbxi_find_child(node, name);
  6206. if (!child) return 0;
  6207. if (!ufbxi_get_val_at(child, 0, fmt[0], v0)) return 0;
  6208. if (!ufbxi_get_val_at(child, 1, fmt[1], v1)) return 0;
  6209. return 1;
  6210. }
  6211. ufbxi_nodiscard static ufbxi_noinline ufbxi_value_array *ufbxi_find_array(ufbxi_node *node, const char *name, char fmt)
  6212. {
  6213. ufbxi_node *child = ufbxi_find_child(node, name);
  6214. if (!child) return NULL;
  6215. return ufbxi_get_array(child, fmt);
  6216. }
  6217. static ufbxi_node *ufbxi_find_child_strcmp(ufbxi_node *node, const char *name)
  6218. {
  6219. char leading = name[0];
  6220. ufbxi_for(ufbxi_node, c, node->children, node->num_children) {
  6221. if (c->name[0] != leading) continue;
  6222. if (!strcmp(c->name, name)) return c;
  6223. }
  6224. return NULL;
  6225. }
  6226. // -- Element extra data allocation
  6227. ufbxi_nodiscard static ufbxi_noinline void *ufbxi_push_element_extra_size(ufbxi_context *uc, uint32_t id, size_t size)
  6228. {
  6229. if (uc->element_extra_cap <= id) {
  6230. size_t old_cap = uc->element_extra_cap;
  6231. ufbxi_check_return(ufbxi_grow_array(&uc->ator_tmp, &uc->element_extra_arr, &uc->element_extra_cap, id + 1), NULL);
  6232. memset(uc->element_extra_arr + old_cap, 0, (uc->element_extra_cap - old_cap) * sizeof(void*));
  6233. }
  6234. if (uc->element_extra_arr[id]) return uc->element_extra_arr[id];
  6235. void *extra = ufbxi_push_size_zero(&uc->tmp, size, 1);
  6236. ufbxi_check_return(extra, NULL);
  6237. uc->element_extra_arr[id] = extra;
  6238. return extra;
  6239. }
  6240. static ufbxi_noinline void *ufbxi_get_element_extra(ufbxi_context *uc, uint32_t id)
  6241. {
  6242. if (id < uc->element_extra_cap) {
  6243. return uc->element_extra_arr[id];
  6244. } else {
  6245. return NULL;
  6246. }
  6247. }
  6248. #define ufbxi_push_element_extra(uc, id, type) (type*)ufbxi_push_element_extra_size((uc), (id), sizeof(type))
  6249. // -- Parsing state machine
  6250. //
  6251. // When reading the file we maintain a coarse representation of the structure so
  6252. // that we can resolve array info (type, included in result, etc). Using this info
  6253. // we can often read/decompress the contents directly into the right memory area.
  6254. typedef enum {
  6255. UFBXI_PARSE_ROOT,
  6256. UFBXI_PARSE_FBX_HEADER_EXTENSION,
  6257. UFBXI_PARSE_SCENE_INFO,
  6258. UFBXI_PARSE_THUMBNAIL,
  6259. UFBXI_PARSE_DEFINITIONS,
  6260. UFBXI_PARSE_OBJECTS,
  6261. UFBXI_PARSE_CONNECTIONS,
  6262. UFBXI_PARSE_RELATIONS,
  6263. UFBXI_PARSE_TAKES,
  6264. UFBXI_PARSE_FBX_VERSION,
  6265. UFBXI_PARSE_MODEL,
  6266. UFBXI_PARSE_GEOMETRY,
  6267. UFBXI_PARSE_NODE_ATTRIBUTE,
  6268. UFBXI_PARSE_LEGACY_MODEL,
  6269. UFBXI_PARSE_LEGACY_MEDIA,
  6270. UFBXI_PARSE_LEGACY_VIDEO,
  6271. UFBXI_PARSE_LEGACY_SWITCHER,
  6272. UFBXI_PARSE_LEGACY_SCENE_PERSISTENCE,
  6273. UFBXI_PARSE_REFERENCES,
  6274. UFBXI_PARSE_REFERENCE,
  6275. UFBXI_PARSE_ANIMATION_CURVE,
  6276. UFBXI_PARSE_DEFORMER,
  6277. UFBXI_PARSE_ASSOCIATE_MODEL,
  6278. UFBXI_PARSE_LEGACY_LINK,
  6279. UFBXI_PARSE_POSE,
  6280. UFBXI_PARSE_POSE_NODE,
  6281. UFBXI_PARSE_TEXTURE,
  6282. UFBXI_PARSE_VIDEO,
  6283. UFBXI_PARSE_LAYERED_TEXTURE,
  6284. UFBXI_PARSE_SELECTION_NODE,
  6285. UFBXI_PARSE_COLLECTION,
  6286. UFBXI_PARSE_AUDIO,
  6287. UFBXI_PARSE_UNKNOWN_OBJECT,
  6288. UFBXI_PARSE_LAYER_ELEMENT_NORMAL,
  6289. UFBXI_PARSE_LAYER_ELEMENT_BINORMAL,
  6290. UFBXI_PARSE_LAYER_ELEMENT_TANGENT,
  6291. UFBXI_PARSE_LAYER_ELEMENT_UV,
  6292. UFBXI_PARSE_LAYER_ELEMENT_COLOR,
  6293. UFBXI_PARSE_LAYER_ELEMENT_VERTEX_CREASE,
  6294. UFBXI_PARSE_LAYER_ELEMENT_EDGE_CREASE,
  6295. UFBXI_PARSE_LAYER_ELEMENT_SMOOTHING,
  6296. UFBXI_PARSE_LAYER_ELEMENT_VISIBILITY,
  6297. UFBXI_PARSE_LAYER_ELEMENT_POLYGON_GROUP,
  6298. UFBXI_PARSE_LAYER_ELEMENT_HOLE,
  6299. UFBXI_PARSE_LAYER_ELEMENT_MATERIAL,
  6300. UFBXI_PARSE_LAYER_ELEMENT_OTHER,
  6301. UFBXI_PARSE_GEOMETRY_UV_INFO,
  6302. UFBXI_PARSE_SHAPE,
  6303. UFBXI_PARSE_TAKE,
  6304. UFBXI_PARSE_TAKE_OBJECT,
  6305. UFBXI_PARSE_CHANNEL,
  6306. UFBXI_PARSE_UNKNOWN,
  6307. } ufbxi_parse_state;
  6308. typedef enum {
  6309. UFBXI_ARRAY_FLAG_RESULT = 0x1, // < Alloacte the array from the result buffer
  6310. UFBXI_ARRAY_FLAG_TMP_BUF = 0x2, // < Alloacte the array from the result buffer
  6311. UFBXI_ARRAY_FLAG_PAD_BEGIN = 0x4, // < Pad the begin of the array with 4 zero elements to guard from invalid -1 index accesses
  6312. UFBXI_ARRAY_FLAG_ACCURATE_F32 = 0x8, // < Must be parsed as bit-accurate 32-bit floats
  6313. } ufbxi_array_flags;
  6314. typedef struct {
  6315. char type; // < FBX type code of the array: b,i,l,f,d (or 'r' meaning ufbx_real '-' ignore, 's'/'S' for strings, 'C' for content)
  6316. uint8_t flags; // < Combination of `ufbxi_array_flags`
  6317. } ufbxi_array_info;
  6318. static ufbxi_noinline ufbxi_parse_state ufbxi_update_parse_state(ufbxi_parse_state parent, const char *name)
  6319. {
  6320. switch (parent) {
  6321. case UFBXI_PARSE_ROOT:
  6322. if (name == ufbxi_FBXHeaderExtension) return UFBXI_PARSE_FBX_HEADER_EXTENSION;
  6323. if (name == ufbxi_Definitions) return UFBXI_PARSE_DEFINITIONS;
  6324. if (name == ufbxi_Objects) return UFBXI_PARSE_OBJECTS;
  6325. if (name == ufbxi_Connections) return UFBXI_PARSE_CONNECTIONS;
  6326. if (name == ufbxi_Takes) return UFBXI_PARSE_TAKES;
  6327. if (name == ufbxi_Model) return UFBXI_PARSE_LEGACY_MODEL;
  6328. if (!strcmp(name, "References")) return UFBXI_PARSE_REFERENCES;
  6329. if (!strcmp(name, "Relations")) return UFBXI_PARSE_RELATIONS;
  6330. if (name == ufbxi_Media) return UFBXI_PARSE_LEGACY_MEDIA;
  6331. if (!strcmp(name, "Switcher")) return UFBXI_PARSE_LEGACY_SWITCHER;
  6332. if (!strcmp(name, "SceneGenericPersistence")) return UFBXI_PARSE_LEGACY_SCENE_PERSISTENCE;
  6333. break;
  6334. case UFBXI_PARSE_FBX_HEADER_EXTENSION:
  6335. if (name == ufbxi_FBXVersion) return UFBXI_PARSE_FBX_VERSION;
  6336. if (name == ufbxi_SceneInfo) return UFBXI_PARSE_SCENE_INFO;
  6337. break;
  6338. case UFBXI_PARSE_SCENE_INFO:
  6339. if (name == ufbxi_Thumbnail) return UFBXI_PARSE_THUMBNAIL;
  6340. break;
  6341. case UFBXI_PARSE_OBJECTS:
  6342. if (name == ufbxi_Model) return UFBXI_PARSE_MODEL;
  6343. if (name == ufbxi_Geometry) return UFBXI_PARSE_GEOMETRY;
  6344. if (name == ufbxi_NodeAttribute) return UFBXI_PARSE_NODE_ATTRIBUTE;
  6345. if (name == ufbxi_AnimationCurve) return UFBXI_PARSE_ANIMATION_CURVE;
  6346. if (name == ufbxi_Deformer) return UFBXI_PARSE_DEFORMER;
  6347. if (name == ufbxi_Pose) return UFBXI_PARSE_POSE;
  6348. if (name == ufbxi_Texture) return UFBXI_PARSE_TEXTURE;
  6349. if (name == ufbxi_Video) return UFBXI_PARSE_VIDEO;
  6350. if (name == ufbxi_LayeredTexture) return UFBXI_PARSE_LAYERED_TEXTURE;
  6351. if (name == ufbxi_SelectionNode) return UFBXI_PARSE_SELECTION_NODE;
  6352. if (name == ufbxi_Collection) return UFBXI_PARSE_COLLECTION;
  6353. if (name == ufbxi_Audio) return UFBXI_PARSE_AUDIO;
  6354. return UFBXI_PARSE_UNKNOWN_OBJECT;
  6355. case UFBXI_PARSE_MODEL:
  6356. case UFBXI_PARSE_GEOMETRY:
  6357. if (name[0] == 'L') {
  6358. if (name == ufbxi_LayerElementNormal) return UFBXI_PARSE_LAYER_ELEMENT_NORMAL;
  6359. if (name == ufbxi_LayerElementBinormal) return UFBXI_PARSE_LAYER_ELEMENT_BINORMAL;
  6360. if (name == ufbxi_LayerElementTangent) return UFBXI_PARSE_LAYER_ELEMENT_TANGENT;
  6361. if (name == ufbxi_LayerElementUV) return UFBXI_PARSE_LAYER_ELEMENT_UV;
  6362. if (name == ufbxi_LayerElementColor) return UFBXI_PARSE_LAYER_ELEMENT_COLOR;
  6363. if (name == ufbxi_LayerElementVertexCrease) return UFBXI_PARSE_LAYER_ELEMENT_VERTEX_CREASE;
  6364. if (name == ufbxi_LayerElementEdgeCrease) return UFBXI_PARSE_LAYER_ELEMENT_EDGE_CREASE;
  6365. if (name == ufbxi_LayerElementSmoothing) return UFBXI_PARSE_LAYER_ELEMENT_SMOOTHING;
  6366. if (name == ufbxi_LayerElementVisibility) return UFBXI_PARSE_LAYER_ELEMENT_VISIBILITY;
  6367. if (name == ufbxi_LayerElementPolygonGroup) return UFBXI_PARSE_LAYER_ELEMENT_POLYGON_GROUP;
  6368. if (name == ufbxi_LayerElementHole) return UFBXI_PARSE_LAYER_ELEMENT_HOLE;
  6369. if (name == ufbxi_LayerElementMaterial) return UFBXI_PARSE_LAYER_ELEMENT_MATERIAL;
  6370. if (!strncmp(name, "LayerElement", 12)) return UFBXI_PARSE_LAYER_ELEMENT_OTHER;
  6371. }
  6372. if (name == ufbxi_Shape) return UFBXI_PARSE_SHAPE;
  6373. break;
  6374. case UFBXI_PARSE_DEFORMER:
  6375. if (!strcmp(name, "AssociateModel")) return UFBXI_PARSE_ASSOCIATE_MODEL;
  6376. break;
  6377. case UFBXI_PARSE_LEGACY_MEDIA:
  6378. if (name == ufbxi_Video) return UFBXI_PARSE_LEGACY_VIDEO;
  6379. break;
  6380. case UFBXI_PARSE_LEGACY_VIDEO:
  6381. return UFBXI_PARSE_VIDEO;
  6382. case UFBXI_PARSE_LEGACY_MODEL:
  6383. if (name == ufbxi_GeometryUVInfo) return UFBXI_PARSE_GEOMETRY_UV_INFO;
  6384. if (name == ufbxi_Link) return UFBXI_PARSE_LEGACY_LINK;
  6385. if (name == ufbxi_Channel) return UFBXI_PARSE_CHANNEL;
  6386. if (name == ufbxi_Shape) return UFBXI_PARSE_SHAPE;
  6387. break;
  6388. case UFBXI_PARSE_POSE:
  6389. if (name == ufbxi_PoseNode) return UFBXI_PARSE_POSE_NODE;
  6390. break;
  6391. case UFBXI_PARSE_TAKES:
  6392. if (name == ufbxi_Take) return UFBXI_PARSE_TAKE;
  6393. break;
  6394. case UFBXI_PARSE_TAKE:
  6395. return UFBXI_PARSE_TAKE_OBJECT;
  6396. case UFBXI_PARSE_TAKE_OBJECT:
  6397. if (name == ufbxi_Channel) return UFBXI_PARSE_CHANNEL;
  6398. break;
  6399. case UFBXI_PARSE_CHANNEL:
  6400. if (name == ufbxi_Channel) return UFBXI_PARSE_CHANNEL;
  6401. break;
  6402. case UFBXI_PARSE_REFERENCES:
  6403. return UFBXI_PARSE_REFERENCE;
  6404. default:
  6405. break;
  6406. }
  6407. return UFBXI_PARSE_UNKNOWN;
  6408. }
  6409. static bool ufbxi_is_array_node(ufbxi_context *uc, ufbxi_parse_state parent, const char *name, ufbxi_array_info *info)
  6410. {
  6411. info->flags = 0;
  6412. // Retain all arrays if user wants the DOM representation
  6413. if (uc->opts.retain_dom) {
  6414. info->flags |= UFBXI_ARRAY_FLAG_RESULT;
  6415. }
  6416. switch (parent) {
  6417. case UFBXI_PARSE_THUMBNAIL:
  6418. if (name == ufbxi_ImageData) {
  6419. info->type = 'c';
  6420. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6421. return true;
  6422. }
  6423. break;
  6424. case UFBXI_PARSE_GEOMETRY:
  6425. case UFBXI_PARSE_MODEL:
  6426. if (name == ufbxi_Vertices) {
  6427. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6428. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6429. return true;
  6430. } else if (name == ufbxi_PolygonVertexIndex) {
  6431. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6432. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6433. return true;
  6434. } else if (name == ufbxi_Edges) {
  6435. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6436. return true;
  6437. } else if (name == ufbxi_Indexes) {
  6438. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6439. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6440. return true;
  6441. } else if (name == ufbxi_Points) {
  6442. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6443. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6444. return true;
  6445. } else if (name == ufbxi_KnotVector) {
  6446. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6447. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6448. return true;
  6449. } else if (name == ufbxi_KnotVectorU) {
  6450. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6451. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6452. return true;
  6453. } else if (name == ufbxi_KnotVectorV) {
  6454. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6455. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6456. return true;
  6457. } else if (name == ufbxi_PointsIndex) {
  6458. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6459. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6460. return true;
  6461. } else if (name == ufbxi_Normals) {
  6462. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6463. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6464. return true;
  6465. }
  6466. break;
  6467. case UFBXI_PARSE_LEGACY_MODEL:
  6468. if (name == ufbxi_Vertices) {
  6469. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6470. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6471. return true;
  6472. } else if (name == ufbxi_Normals) {
  6473. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6474. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6475. return true;
  6476. } else if (name == ufbxi_Materials) {
  6477. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6478. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6479. return true;
  6480. } else if (name == ufbxi_PolygonVertexIndex) {
  6481. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6482. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6483. return true;
  6484. } else if (name == ufbxi_Children) {
  6485. info->type = 's';
  6486. return true;
  6487. }
  6488. break;
  6489. case UFBXI_PARSE_ANIMATION_CURVE:
  6490. if (name == ufbxi_KeyTime) {
  6491. info->type = uc->opts.ignore_animation ? '-' : 'l';
  6492. return true;
  6493. } else if (name == ufbxi_KeyValueFloat) {
  6494. info->type = uc->opts.ignore_animation ? '-' : 'r';
  6495. return true;
  6496. } else if (name == ufbxi_KeyAttrFlags) {
  6497. info->type = uc->opts.ignore_animation ? '-' : 'i';
  6498. return true;
  6499. } else if (name == ufbxi_KeyAttrDataFloat) {
  6500. // The float data in a keyframe attribute array is represented as integers
  6501. // in versions >= 7200 as some of the elements aren't actually floats (!)
  6502. info->type = uc->from_ascii && uc->version >= 7200 ? 'i' : 'f';
  6503. if (uc->opts.ignore_animation) info->type = '-';
  6504. if (uc->from_ascii && uc->version >= 7200) {
  6505. info->flags |= UFBXI_ARRAY_FLAG_ACCURATE_F32;
  6506. }
  6507. return true;
  6508. } else if (name == ufbxi_KeyAttrRefCount) {
  6509. info->type = uc->opts.ignore_animation ? '-' : 'i';
  6510. return true;
  6511. }
  6512. break;
  6513. case UFBXI_PARSE_TEXTURE:
  6514. if (!strcmp(name, "ModelUVTranslation") || !strcmp(name, "ModelUVScaling") || !strcmp(name, "Cropping")) {
  6515. info->type = uc->opts.retain_dom ? 'r' : '-';
  6516. return true;
  6517. }
  6518. break;
  6519. case UFBXI_PARSE_VIDEO:
  6520. if (name == ufbxi_Content) {
  6521. info->type = uc->opts.ignore_embedded ? '-' : 'C';
  6522. return true;
  6523. }
  6524. break;
  6525. case UFBXI_PARSE_LAYERED_TEXTURE:
  6526. if (name == ufbxi_BlendModes) {
  6527. info->type = 'i';
  6528. info->flags |= UFBXI_ARRAY_FLAG_TMP_BUF;
  6529. return true;
  6530. } else if (name == ufbxi_Alphas) {
  6531. info->type = 'r';
  6532. info->flags |= UFBXI_ARRAY_FLAG_TMP_BUF;
  6533. return true;
  6534. }
  6535. break;
  6536. case UFBXI_PARSE_SELECTION_NODE:
  6537. if (name == ufbxi_VertexIndexArray) {
  6538. info->type = 'i';
  6539. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6540. return true;
  6541. } else if (name == ufbxi_EdgeIndexArray) {
  6542. info->type = 'i';
  6543. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6544. return true;
  6545. } else if (name == ufbxi_PolygonIndexArray) {
  6546. info->type = 'i';
  6547. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6548. return true;
  6549. }
  6550. break;
  6551. case UFBXI_PARSE_LAYER_ELEMENT_NORMAL:
  6552. if (name == ufbxi_Normals) {
  6553. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6554. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6555. return true;
  6556. } else if (name == ufbxi_NormalsIndex) {
  6557. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6558. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6559. return true;
  6560. } else if (name == ufbxi_NormalsW) {
  6561. info->type = uc->retain_vertex_w ? 'r' : '-';
  6562. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6563. return true;
  6564. }
  6565. break;
  6566. case UFBXI_PARSE_LAYER_ELEMENT_BINORMAL:
  6567. if (name == ufbxi_Binormals) {
  6568. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6569. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6570. return true;
  6571. } else if (name == ufbxi_BinormalsIndex) {
  6572. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6573. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6574. return true;
  6575. } else if (name == ufbxi_BinormalsW) {
  6576. info->type = uc->retain_vertex_w ? 'r' : '-';
  6577. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6578. return true;
  6579. }
  6580. break;
  6581. case UFBXI_PARSE_LAYER_ELEMENT_TANGENT:
  6582. if (name == ufbxi_Tangents) {
  6583. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6584. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6585. return true;
  6586. } else if (name == ufbxi_TangentsIndex) {
  6587. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6588. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6589. return true;
  6590. } else if (name == ufbxi_TangentsW) {
  6591. info->type = uc->retain_vertex_w ? 'r' : '-';
  6592. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6593. return true;
  6594. }
  6595. break;
  6596. case UFBXI_PARSE_LAYER_ELEMENT_UV:
  6597. if (name == ufbxi_UV) {
  6598. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6599. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6600. return true;
  6601. } else if (name == ufbxi_UVIndex) {
  6602. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6603. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6604. return true;
  6605. }
  6606. break;
  6607. case UFBXI_PARSE_LAYER_ELEMENT_COLOR:
  6608. if (name == ufbxi_Colors) {
  6609. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6610. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6611. return true;
  6612. } else if (name == ufbxi_ColorIndex) {
  6613. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6614. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6615. return true;
  6616. }
  6617. break;
  6618. case UFBXI_PARSE_LAYER_ELEMENT_VERTEX_CREASE:
  6619. if (name == ufbxi_VertexCrease) {
  6620. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6621. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6622. return true;
  6623. } else if (name == ufbxi_VertexCreaseIndex) {
  6624. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6625. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6626. return true;
  6627. }
  6628. break;
  6629. case UFBXI_PARSE_LAYER_ELEMENT_EDGE_CREASE:
  6630. if (name == ufbxi_EdgeCrease) {
  6631. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6632. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6633. return true;
  6634. }
  6635. break;
  6636. case UFBXI_PARSE_LAYER_ELEMENT_SMOOTHING:
  6637. if (name == ufbxi_Smoothing) {
  6638. info->type = uc->opts.ignore_geometry ? '-' : 'b';
  6639. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6640. return true;
  6641. }
  6642. break;
  6643. case UFBXI_PARSE_LAYER_ELEMENT_VISIBILITY:
  6644. if (name == ufbxi_Visibility) {
  6645. info->type = uc->opts.ignore_geometry ? '-' : 'b';
  6646. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6647. return true;
  6648. }
  6649. break;
  6650. case UFBXI_PARSE_LAYER_ELEMENT_POLYGON_GROUP:
  6651. if (name == ufbxi_PolygonGroup) {
  6652. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6653. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6654. return true;
  6655. }
  6656. break;
  6657. case UFBXI_PARSE_LAYER_ELEMENT_HOLE:
  6658. if (name == ufbxi_Hole) {
  6659. info->type = uc->opts.ignore_geometry ? '-' : 'b';
  6660. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6661. return true;
  6662. }
  6663. break;
  6664. case UFBXI_PARSE_LAYER_ELEMENT_MATERIAL:
  6665. if (name == ufbxi_Materials) {
  6666. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6667. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6668. return true;
  6669. }
  6670. break;
  6671. case UFBXI_PARSE_LAYER_ELEMENT_OTHER:
  6672. if (name == ufbxi_TextureId) {
  6673. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6674. info->flags |= UFBXI_ARRAY_FLAG_TMP_BUF;
  6675. return true;
  6676. } else if (name == ufbxi_UV) {
  6677. info->type = uc->opts.retain_dom ? 'r' : '-';
  6678. return true;
  6679. } else if (name == ufbxi_UVIndex) {
  6680. info->type = uc->opts.retain_dom ? 'i' : '-';
  6681. return true;
  6682. }
  6683. break;
  6684. case UFBXI_PARSE_GEOMETRY_UV_INFO:
  6685. if (name == ufbxi_TextureUV) {
  6686. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6687. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6688. return true;
  6689. } else if (name == ufbxi_TextureUVVerticeIndex) {
  6690. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6691. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6692. return true;
  6693. }
  6694. break;
  6695. case UFBXI_PARSE_SHAPE:
  6696. if (name == ufbxi_Indexes) {
  6697. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6698. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6699. return true;
  6700. }
  6701. if (name == ufbxi_Vertices) {
  6702. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6703. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6704. return true;
  6705. }
  6706. if (name == ufbxi_Normals) {
  6707. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6708. info->flags = UFBXI_ARRAY_FLAG_RESULT | UFBXI_ARRAY_FLAG_PAD_BEGIN;
  6709. return true;
  6710. }
  6711. break;
  6712. case UFBXI_PARSE_DEFORMER:
  6713. if (name == ufbxi_Transform) {
  6714. info->type = 'r';
  6715. return true;
  6716. } else if (name == ufbxi_TransformLink) {
  6717. info->type = 'r';
  6718. return true;
  6719. } else if (name == ufbxi_Indexes) {
  6720. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6721. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6722. return true;
  6723. } else if (name == ufbxi_Weights) {
  6724. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6725. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6726. return true;
  6727. } else if (name == ufbxi_BlendWeights) {
  6728. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6729. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6730. return true;
  6731. } else if (name == ufbxi_FullWeights) {
  6732. // Ignore blend shape FullWeights as it's used in Blender for vertex groups
  6733. // which we don't currently handle. https://developer.blender.org/T90382
  6734. // TODO: Should we present this to users anyway somehow?
  6735. info->type = 'r';
  6736. if (!uc->opts.disable_quirks && uc->exporter == UFBX_EXPORTER_BLENDER_BINARY) {
  6737. info->type = '-';
  6738. }
  6739. info->flags |= UFBXI_ARRAY_FLAG_TMP_BUF;
  6740. return true;
  6741. } else if (!strcmp(name, "TransformAssociateModel")) {
  6742. info->type = uc->opts.retain_dom ? 'r' : '-';
  6743. return true;
  6744. }
  6745. break;
  6746. case UFBXI_PARSE_ASSOCIATE_MODEL:
  6747. if (name == ufbxi_Transform) {
  6748. info->type = uc->opts.retain_dom ? 'r' : '-';
  6749. return true;
  6750. }
  6751. break;
  6752. case UFBXI_PARSE_LEGACY_LINK:
  6753. if (name == ufbxi_Transform) {
  6754. info->type = 'r';
  6755. return true;
  6756. } else if (name == ufbxi_TransformLink) {
  6757. info->type = 'r';
  6758. return true;
  6759. } else if (name == ufbxi_Indexes) {
  6760. info->type = uc->opts.ignore_geometry ? '-' : 'i';
  6761. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6762. return true;
  6763. } else if (name == ufbxi_Weights) {
  6764. info->type = uc->opts.ignore_geometry ? '-' : 'r';
  6765. info->flags = UFBXI_ARRAY_FLAG_RESULT;
  6766. return true;
  6767. }
  6768. break;
  6769. case UFBXI_PARSE_POSE_NODE:
  6770. if (name == ufbxi_Matrix) {
  6771. info->type = 'r';
  6772. return true;
  6773. }
  6774. break;
  6775. case UFBXI_PARSE_CHANNEL:
  6776. if (name == ufbxi_Key) {
  6777. info->type = uc->opts.ignore_animation ? '-' : 'd';
  6778. return true;
  6779. }
  6780. break;
  6781. case UFBXI_PARSE_AUDIO:
  6782. if (name == ufbxi_Content) {
  6783. info->type = uc->opts.ignore_embedded ? '-' : 'C';
  6784. return true;
  6785. }
  6786. break;
  6787. default:
  6788. if (name == ufbxi_BinaryData) {
  6789. info->type = uc->opts.ignore_embedded ? '-' : 'C';
  6790. return true;
  6791. }
  6792. break;
  6793. }
  6794. return false;
  6795. }
  6796. static ufbxi_noinline bool ufbxi_is_raw_string(ufbxi_context *uc, ufbxi_parse_state parent, const char *name, size_t index)
  6797. {
  6798. (void)index;
  6799. switch (parent) {
  6800. case UFBXI_PARSE_ROOT:
  6801. if (name == ufbxi_Model) return true;
  6802. if (!strcmp(name, "FileId")) return true;
  6803. break;
  6804. case UFBXI_PARSE_FBX_HEADER_EXTENSION:
  6805. if (name == ufbxi_SceneInfo) return true;
  6806. break;
  6807. case UFBXI_PARSE_OBJECTS:
  6808. return true;
  6809. case UFBXI_PARSE_CONNECTIONS:
  6810. case UFBXI_PARSE_RELATIONS:
  6811. // Pre-7000 needs raw strings for "Name\x00\x01Type" pairs, post-7000 uses it only
  6812. // for properties that are non-raw by default.
  6813. return uc->version < 7000;
  6814. case UFBXI_PARSE_MODEL:
  6815. if (name == ufbxi_NodeAttributeName) return true;
  6816. if (name == ufbxi_Name) return true;
  6817. break;
  6818. case UFBXI_PARSE_VIDEO:
  6819. if (name == ufbxi_Content) return true;
  6820. break;
  6821. case UFBXI_PARSE_TEXTURE:
  6822. if (!strcmp(name, "TextureName")) return true;
  6823. if (name == ufbxi_Media) return true;
  6824. break;
  6825. case UFBXI_PARSE_GEOMETRY:
  6826. if (name == ufbxi_NodeAttributeName) return true;
  6827. if (name == ufbxi_Name) return true;
  6828. break;
  6829. case UFBXI_PARSE_NODE_ATTRIBUTE:
  6830. if (name == ufbxi_NodeAttributeName) return true;
  6831. if (name == ufbxi_Name) return true;
  6832. break;
  6833. case UFBXI_PARSE_POSE_NODE:
  6834. if (name == ufbxi_Node) return true;
  6835. break;
  6836. case UFBXI_PARSE_SELECTION_NODE:
  6837. if (name == ufbxi_Node) return true;
  6838. break;
  6839. case UFBXI_PARSE_UNKNOWN_OBJECT:
  6840. if (name == ufbxi_NodeAttributeName) return true;
  6841. if (name == ufbxi_Name) return true;
  6842. break;
  6843. case UFBXI_PARSE_COLLECTION:
  6844. if (!strcmp(name, "Member")) return true;
  6845. break;
  6846. case UFBXI_PARSE_AUDIO:
  6847. if (name == ufbxi_Content) return true;
  6848. break;
  6849. case UFBXI_PARSE_LEGACY_MODEL:
  6850. if (name == ufbxi_Material) return true;
  6851. if (name == ufbxi_Link) return true;
  6852. if (name == ufbxi_Name) return true;
  6853. break;
  6854. case UFBXI_PARSE_LEGACY_SWITCHER:
  6855. if (!strcmp(name, "CameraIndexName")) return true;
  6856. break;
  6857. case UFBXI_PARSE_LEGACY_SCENE_PERSISTENCE:
  6858. if (name == ufbxi_SceneInfo) return true;
  6859. break;
  6860. case UFBXI_PARSE_REFERENCE:
  6861. if (!strcmp(name, "Object")) return true;
  6862. break;
  6863. case UFBXI_PARSE_TAKE:
  6864. if (name == ufbxi_Model) return true;
  6865. break;
  6866. default:
  6867. break;
  6868. }
  6869. return false;
  6870. }
  6871. // -- Binary parsing
  6872. ufbxi_nodiscard static ufbxi_noinline char *ufbxi_swap_endian(ufbxi_context *uc, const void *src, size_t count, size_t elem_size)
  6873. {
  6874. ufbxi_dev_assert(elem_size > 1);
  6875. size_t total_size = count * elem_size;
  6876. ufbxi_check_return(!ufbxi_does_overflow(total_size, count, elem_size), NULL);
  6877. if (uc->swap_arr_size < total_size) {
  6878. ufbxi_check_return(ufbxi_grow_array(&uc->ator_tmp, &uc->swap_arr, &uc->swap_arr_size, total_size), NULL);
  6879. }
  6880. char *dst = uc->swap_arr, *d = dst;
  6881. const char *s = (const char*)src;
  6882. switch (elem_size) {
  6883. case 2:
  6884. ufbxi_nounroll for (size_t i = 0; i < count; i++) {
  6885. d[0] = s[1]; d[1] = s[0];
  6886. d += 2; s += 2;
  6887. }
  6888. break;
  6889. case 4:
  6890. ufbxi_nounroll for (size_t i = 0; i < count; i++) {
  6891. d[0] = s[3]; d[1] = s[2]; d[2] = s[1]; d[3] = s[0];
  6892. d += 4; s += 4;
  6893. }
  6894. break;
  6895. case 8:
  6896. ufbxi_nounroll for (size_t i = 0; i < count; i++) {
  6897. d[0] = s[7]; d[1] = s[6]; d[2] = s[5]; d[3] = s[4];
  6898. d[4] = s[3]; d[5] = s[2]; d[6] = s[1]; d[7] = s[0];
  6899. d += 8; s += 8;
  6900. }
  6901. break;
  6902. default:
  6903. ufbxi_unreachable("Bad endian swap size");
  6904. }
  6905. return dst;
  6906. }
  6907. // Swap the endianness of an array typed with a lowercase letter
  6908. ufbxi_nodiscard static ufbxi_noinline const char *ufbxi_swap_endian_array(ufbxi_context *uc, const void *src, size_t count, char type)
  6909. {
  6910. switch (type) {
  6911. case 'i': case 'f': return ufbxi_swap_endian(uc, src, count, 4);
  6912. case 'l': case 'd': return ufbxi_swap_endian(uc, src, count, 8);
  6913. default: return (const char*)src;
  6914. }
  6915. }
  6916. // Swap the endianness of a single value (shallow, swaps string/array header words)
  6917. ufbxi_nodiscard static ufbxi_noinline const char *ufbxi_swap_endian_value(ufbxi_context *uc, const void *src, char type)
  6918. {
  6919. switch (type) {
  6920. case 'Y': return ufbxi_swap_endian(uc, src, 1, 2);
  6921. case 'I': case 'F': return ufbxi_swap_endian(uc, src, 1, 4);
  6922. case 'L': case 'D': return ufbxi_swap_endian(uc, src, 1, 8);
  6923. case 'S': case 'R': return ufbxi_swap_endian(uc, src, 1, 4);
  6924. case 'i': case 'l': case 'f': case 'd': case 'b': return ufbxi_swap_endian(uc, src, 3, 4);
  6925. default: return (const char*)src;
  6926. }
  6927. }
  6928. // Read and convert a post-7000 FBX data array into a different format. `src_type` may be equal to `dst_type`
  6929. // if the platform is not binary compatible with the FBX data representation.
  6930. ufbxi_nodiscard static ufbxi_noinline int ufbxi_binary_convert_array(ufbxi_context *maybe_uc, char src_type, char dst_type, const void *src, void *dst, size_t size)
  6931. {
  6932. // TODO: We might want to use the slow path if the machine float/double doesn't match IEEE 754!
  6933. // Convert commented out lines under some `#if UFBX_NON_IEE754` define or something.
  6934. if (src_type == dst_type) {
  6935. ufbx_assert(maybe_uc && maybe_uc->file_big_endian != maybe_uc->local_big_endian);
  6936. src = ufbxi_swap_endian_array(maybe_uc, src, size, src_type);
  6937. ufbxi_check_err(&maybe_uc->error, src);
  6938. memcpy(dst, src, size * ufbxi_array_type_size(dst_type));
  6939. return 1;
  6940. }
  6941. if (maybe_uc && maybe_uc->file_big_endian) {
  6942. src = ufbxi_swap_endian_array(maybe_uc, src, size, src_type);
  6943. ufbxi_check_err(&maybe_uc->error, src);
  6944. }
  6945. switch (dst_type)
  6946. {
  6947. #define ufbxi_convert_loop_fast(m_dst, m_cast, m_size, m_expr) do { \
  6948. const char *val = (const char*)src, *val_end = val + size*m_size; \
  6949. m_dst *d = (m_dst*)dst; \
  6950. while (val != val_end) { *d++ = m_cast(m_expr); val += m_size; } \
  6951. } while (0)
  6952. #define ufbxi_convert_loop_slow(m_dst, m_cast, m_size, m_expr) do { \
  6953. const char *val = (const char*)src, *val_end = val + size*m_size; \
  6954. m_dst *d = (m_dst*)dst; \
  6955. ufbxi_nounroll while (val != val_end) { *d++ = m_cast(m_expr); val += m_size; } \
  6956. } while (0)
  6957. case 'c':
  6958. switch (src_type) {
  6959. // case 'c': ufbxi_convert_loop_fast(char, (char), 1, *val != 0); break;
  6960. case 'i': ufbxi_convert_loop_slow(uint8_t, (uint8_t), 4, (uint8_t)ufbxi_read_i32(val)); break;
  6961. case 'l': ufbxi_convert_loop_slow(uint8_t, (uint8_t), 8, (uint8_t)ufbxi_read_i64(val)); break;
  6962. case 'f': ufbxi_convert_loop_slow(uint8_t, (uint8_t), 4, (uint8_t)ufbxi_read_f32(val)); break;
  6963. case 'd': ufbxi_convert_loop_slow(uint8_t, (uint8_t), 8, (uint8_t)ufbxi_read_f64(val)); break;
  6964. default: if (maybe_uc) ufbxi_fail_err(&maybe_uc->error, "Bad array source type"); return 0;
  6965. }
  6966. break;
  6967. case 'i':
  6968. switch (src_type) {
  6969. case 'c': ufbxi_convert_loop_slow(int32_t, (int32_t), 1, *val); break;
  6970. // case 'i': ufbxi_convert_loop_slow(int32_t, (int32_t), 4, ufbxi_read_i32(val)); break;
  6971. case 'l': ufbxi_convert_loop_slow(int32_t, (int32_t), 8, ufbxi_read_i64(val)); break;
  6972. case 'f': ufbxi_convert_loop_slow(int32_t, ufbxi_f64_to_i32, 4, ufbxi_read_f32(val)); break;
  6973. case 'd': ufbxi_convert_loop_slow(int32_t, ufbxi_f64_to_i32, 8, ufbxi_read_f64(val)); break;
  6974. default: if (maybe_uc) ufbxi_fail_err(&maybe_uc->error, "Bad array source type"); return 0;
  6975. }
  6976. break;
  6977. case 'l':
  6978. switch (src_type) {
  6979. case 'c': ufbxi_convert_loop_slow(int64_t, (int64_t), 1, *val); break;
  6980. case 'i': ufbxi_convert_loop_slow(int64_t, (int64_t), 4, ufbxi_read_i32(val)); break;
  6981. // case 'l': ufbxi_convert_loop_slow(int64_t, (int64_t), 8, ufbxi_read_i64(val)); break;
  6982. case 'f': ufbxi_convert_loop_slow(int64_t, ufbxi_f64_to_i64, 4, ufbxi_read_f32(val)); break;
  6983. case 'd': ufbxi_convert_loop_slow(int64_t, ufbxi_f64_to_i64, 8, ufbxi_read_f64(val)); break;
  6984. default: if (maybe_uc) ufbxi_fail_err(&maybe_uc->error, "Bad array source type"); return 0;
  6985. }
  6986. break;
  6987. case 'f':
  6988. switch (src_type) {
  6989. case 'c': ufbxi_convert_loop_slow(float, (float), 1, *val); break;
  6990. case 'i': ufbxi_convert_loop_slow(float, (float), 4, ufbxi_read_i32(val)); break;
  6991. case 'l': ufbxi_convert_loop_slow(float, (float), 8, ufbxi_read_i64(val)); break;
  6992. // case 'f': ufbxi_convert_loop_slow(float, (float), 4, ufbxi_read_f32(val)); break;
  6993. case 'd': ufbxi_convert_loop_fast(float, (float), 8, ufbxi_read_f64(val)); break;
  6994. default: if (maybe_uc) ufbxi_fail_err(&maybe_uc->error, "Bad array source type"); return 0;
  6995. }
  6996. break;
  6997. case 'd':
  6998. switch (src_type) {
  6999. case 'c': ufbxi_convert_loop_slow(double, (double), 1, *val); break;
  7000. case 'i': ufbxi_convert_loop_slow(double, (double), 4, ufbxi_read_i32(val)); break;
  7001. case 'l': ufbxi_convert_loop_slow(double, (double), 8, ufbxi_read_i64(val)); break;
  7002. case 'f': ufbxi_convert_loop_fast(double, (double), 4, ufbxi_read_f32(val)); break;
  7003. // case 'd': ufbxi_convert_loop_slow(double, (double), 8, ufbxi_read_f64(val)); break;
  7004. default: if (maybe_uc) ufbxi_fail_err(&maybe_uc->error, "Bad array source type"); return 0;
  7005. }
  7006. break;
  7007. default: return 0;
  7008. }
  7009. return 1;
  7010. }
  7011. // Read pre-7000 separate properties as an array.
  7012. ufbxi_nodiscard static ufbxi_noinline int ufbxi_binary_parse_multivalue_array(ufbxi_context *uc, char dst_type, void *dst, size_t size, ufbxi_buf *tmp_buf)
  7013. {
  7014. if (size == 0) return 1;
  7015. const char *val;
  7016. size_t val_size;
  7017. bool file_big_endian = uc->file_big_endian;
  7018. #define ufbxi_convert_parse_fast(m_dst, m_type, m_expr) do { \
  7019. m_dst *d = (m_dst*)dst; \
  7020. for (; base < size; base++) { \
  7021. val = ufbxi_peek_bytes(uc, 13); \
  7022. ufbxi_check(val); \
  7023. if (*val != m_type) break; \
  7024. val++; \
  7025. *d++ = (m_dst)(m_expr); \
  7026. ufbxi_consume_bytes(uc, 1 + sizeof(m_dst)); \
  7027. } \
  7028. } while (0)
  7029. // String array special case
  7030. if (dst_type == 's' || dst_type == 'S' || dst_type == 'C') {
  7031. bool raw = dst_type == 's';
  7032. ufbx_string *d = (ufbx_string*)dst;
  7033. for (size_t i = 0; i < size; i++) {
  7034. val = ufbxi_peek_bytes(uc, 13);
  7035. ufbxi_check(val);
  7036. char type = *val++;
  7037. ufbxi_check(type == 'S' || type == 'R');
  7038. if (file_big_endian) {
  7039. val = ufbxi_swap_endian_value(uc, val, type);
  7040. ufbxi_check(val);
  7041. }
  7042. size_t len = ufbxi_read_u32(val);
  7043. ufbxi_consume_bytes(uc, 5);
  7044. d->data = ufbxi_read_bytes(uc, len);
  7045. d->length = len;
  7046. ufbxi_check(d->data);
  7047. if (dst_type == 'C') {
  7048. ufbxi_buf *buf = size == 1 || uc->opts.retain_dom ? &uc->result : tmp_buf;
  7049. d->data = ufbxi_push_copy(buf, char, len, d->data);
  7050. ufbxi_check(d->data);
  7051. } else {
  7052. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, d, raw));
  7053. }
  7054. d++;
  7055. }
  7056. return 1;
  7057. }
  7058. // Optimize a couple of common cases
  7059. size_t base = 0;
  7060. if (!file_big_endian) {
  7061. switch (dst_type) {
  7062. case 'i': ufbxi_convert_parse_fast(int32_t, 'I', ufbxi_read_i32(val)); break;
  7063. case 'l': ufbxi_convert_parse_fast(int64_t, 'L', ufbxi_read_i64(val)); break;
  7064. case 'f': ufbxi_convert_parse_fast(float, 'F', ufbxi_read_f32(val)); break;
  7065. case 'd': ufbxi_convert_parse_fast(double, 'D', ufbxi_read_f64(val)); break;
  7066. default: break; // Fallthrough to rest
  7067. }
  7068. // Early return if we handled everything
  7069. if (base == size) return 1;
  7070. }
  7071. switch (dst_type)
  7072. {
  7073. #define ufbxi_convert_parse(m_cast, m_size, m_expr) \
  7074. *d++ = m_cast(m_expr); val_size = m_size + 1; \
  7075. #define ufbxi_convert_parse_switch(m_dst, m_cast_int, m_cast_float) do { \
  7076. m_dst *d = (m_dst*)dst + base; \
  7077. for (size_t i = base; i < size; i++) { \
  7078. val = ufbxi_peek_bytes(uc, 13); \
  7079. ufbxi_check(val); \
  7080. char type = *val++; \
  7081. if (file_big_endian) { \
  7082. val = ufbxi_swap_endian_value(uc, val, type); \
  7083. ufbxi_check(val); \
  7084. } \
  7085. switch (type) { \
  7086. case 'C': \
  7087. case 'B': ufbxi_convert_parse(m_cast_int, 1, *val); break; \
  7088. case 'Y': ufbxi_convert_parse(m_cast_int, 2, ufbxi_read_i16(val)); break; \
  7089. case 'I': ufbxi_convert_parse(m_cast_int, 4, ufbxi_read_i32(val)); break; \
  7090. case 'L': ufbxi_convert_parse(m_cast_int, 8, ufbxi_read_i64(val)); break; \
  7091. case 'F': ufbxi_convert_parse(m_cast_float, 4, ufbxi_read_f32(val)); break; \
  7092. case 'D': ufbxi_convert_parse(m_cast_float, 8, ufbxi_read_f64(val)); break; \
  7093. default: ufbxi_fail("Bad multivalue array type"); \
  7094. } \
  7095. ufbxi_consume_bytes(uc, val_size); \
  7096. } \
  7097. } while (0)
  7098. case 'c': ufbxi_convert_parse_switch(uint8_t, (uint8_t), (uint8_t)); break;
  7099. case 'i': ufbxi_convert_parse_switch(int32_t, (int32_t), ufbxi_f64_to_i32); break;
  7100. case 'l': ufbxi_convert_parse_switch(int64_t, (int64_t), ufbxi_f64_to_i64); break;
  7101. case 'f': ufbxi_convert_parse_switch(float, (float), (float)); break;
  7102. case 'd': ufbxi_convert_parse_switch(double, (double), (double)); break;
  7103. default: return 0;
  7104. }
  7105. return 1;
  7106. }
  7107. ufbxi_nodiscard ufbxi_noinline static void *ufbxi_push_array_data(ufbxi_context *uc, const ufbxi_array_info *info, size_t size, ufbxi_buf *tmp_buf)
  7108. {
  7109. size_t elem_size = ufbxi_array_type_size(info->type);
  7110. uint32_t flags = info->flags;
  7111. if (flags & UFBXI_ARRAY_FLAG_PAD_BEGIN) size += 4;
  7112. // The array may be pushed either to the result or temporary buffer depending
  7113. // if it's already in the right format
  7114. ufbxi_buf *arr_buf = tmp_buf;
  7115. if (flags & UFBXI_ARRAY_FLAG_RESULT) arr_buf = &uc->result;
  7116. else if (flags & UFBXI_ARRAY_FLAG_TMP_BUF) arr_buf = &uc->tmp;
  7117. char *data = (char*)ufbxi_push_size(arr_buf, elem_size, size);
  7118. ufbxi_check_return(data, NULL);
  7119. if (flags & UFBXI_ARRAY_FLAG_PAD_BEGIN) {
  7120. memset(data, 0, elem_size * 4);
  7121. data += elem_size * 4;
  7122. }
  7123. return data;
  7124. }
  7125. ufbxi_noinline static void ufbxi_postprocess_bool_array(char *data, size_t size)
  7126. {
  7127. ufbxi_for(char, b, (char*)data, size) {
  7128. *b = (char)(*b != 0);
  7129. }
  7130. }
  7131. typedef struct {
  7132. size_t encoded_size;
  7133. size_t src_elem_size;
  7134. size_t array_size;
  7135. char src_type;
  7136. char dst_type;
  7137. char arr_type;
  7138. const void *encoded_data;
  7139. void *decoded_data;
  7140. void *dst_data;
  7141. ufbx_inflate_retain *inflate_retain;
  7142. } ufbxi_deflate_task;
  7143. static bool ufbxi_deflate_task_fn(ufbxi_task *task)
  7144. {
  7145. ufbxi_deflate_task *t = (ufbxi_deflate_task*)task->data;
  7146. ufbx_inflate_input input; // ufbxi_uninit
  7147. input.total_size = t->encoded_size;
  7148. input.data = t->encoded_data;
  7149. input.data_size = t->encoded_size;
  7150. input.no_header = false;
  7151. input.no_checksum = false;
  7152. input.internal_fast_bits = 0;
  7153. input.progress_cb.fn = NULL;
  7154. input.progress_cb.user = NULL;
  7155. input.progress_size_before = 0;
  7156. input.progress_size_after = 0;
  7157. input.progress_interval_hint = 0;
  7158. input.buffer = NULL;
  7159. input.buffer_size = 0;
  7160. input.read_fn = NULL;
  7161. input.read_user = NULL;
  7162. size_t decoded_data_size = t->src_elem_size * t->array_size;
  7163. ptrdiff_t res = ufbx_inflate(t->decoded_data, decoded_data_size, &input, t->inflate_retain);
  7164. if (res == -28) {
  7165. task->error = "Cancelled";
  7166. return false;
  7167. } else if (res != (ptrdiff_t)decoded_data_size) {
  7168. task->error = "Bad DEFLATE data";
  7169. return false;
  7170. }
  7171. if (t->decoded_data != t->dst_data) {
  7172. int ok = ufbxi_binary_convert_array(NULL, t->src_type, t->dst_type, t->decoded_data, t->dst_data, t->array_size);
  7173. if (!ok) {
  7174. task->error = "Failed to convert array";
  7175. return false;
  7176. }
  7177. }
  7178. if (t->arr_type == 'b') {
  7179. ufbxi_postprocess_bool_array((char*)t->dst_data, t->array_size);
  7180. }
  7181. return true;
  7182. }
  7183. // Recursion limited by check at the start
  7184. ufbxi_nodiscard ufbxi_noinline static int ufbxi_binary_parse_node(ufbxi_context *uc, uint32_t depth, ufbxi_parse_state parent_state, bool *p_end, ufbxi_buf *tmp_buf, bool recursive)
  7185. ufbxi_recursive_function(int, ufbxi_binary_parse_node, (uc, depth, parent_state, p_end, tmp_buf, recursive), UFBXI_MAX_NODE_DEPTH + 1,
  7186. (ufbxi_context *uc, uint32_t depth, ufbxi_parse_state parent_state, bool *p_end, ufbxi_buf *tmp_buf, bool recursive))
  7187. {
  7188. // https://code.blender.org/2013/08/fbx-binary-file-format-specification
  7189. // Parse an FBX document node in the binary format
  7190. ufbxi_check(depth < UFBXI_MAX_NODE_DEPTH);
  7191. // Parse the node header, post-7500 versions use 64-bit values for most
  7192. // header fields.
  7193. uint64_t end_offset, num_values64, values_len;
  7194. uint8_t name_len;
  7195. size_t header_size = (uc->version >= 7500) ? 25 : 13;
  7196. const char *header = ufbxi_read_bytes(uc, header_size), *header_words = header;
  7197. ufbxi_check(header);
  7198. if (uc->version >= 7500) {
  7199. if (uc->file_big_endian) {
  7200. header_words = ufbxi_swap_endian(uc, header_words, 3, 8);
  7201. ufbxi_check(header_words);
  7202. }
  7203. end_offset = ufbxi_read_u64(header_words + 0);
  7204. num_values64 = ufbxi_read_u64(header_words + 8);
  7205. values_len = ufbxi_read_u64(header_words + 16);
  7206. name_len = ufbxi_read_u8(header + 24);
  7207. } else {
  7208. if (uc->file_big_endian) {
  7209. header_words = ufbxi_swap_endian(uc, header_words, 3, 4);
  7210. ufbxi_check(header_words);
  7211. }
  7212. end_offset = ufbxi_read_u32(header_words + 0);
  7213. num_values64 = ufbxi_read_u32(header_words + 4);
  7214. values_len = ufbxi_read_u32(header_words + 8);
  7215. name_len = ufbxi_read_u8(header + 12);
  7216. }
  7217. ufbxi_check(num_values64 <= UINT32_MAX);
  7218. uint32_t num_values = (uint32_t)num_values64;
  7219. // If `end_offset` and `name_len` is zero we treat as the node as a NULL-sentinel
  7220. // that terminates a node list.
  7221. if (end_offset == 0 && name_len == 0) {
  7222. *p_end = true;
  7223. return 1;
  7224. }
  7225. // Update estimated end offset if possible
  7226. if (end_offset > uc->progress_bytes_total) {
  7227. uc->progress_bytes_total = end_offset;
  7228. }
  7229. // Push the parsed node into the `tmp_stack` buffer, the nodes will be popped by
  7230. // calling code after its done parsing all of it's children.
  7231. ufbxi_node *node = ufbxi_push_zero(&uc->tmp_stack, ufbxi_node, 1);
  7232. ufbxi_check(node);
  7233. // Parse and intern the name to the string pool.
  7234. const char *name = ufbxi_read_bytes(uc, name_len);
  7235. ufbxi_check(name);
  7236. name = ufbxi_push_string(&uc->string_pool, name, name_len, NULL, true);
  7237. ufbxi_check(name);
  7238. node->name_len = name_len;
  7239. node->name = name;
  7240. uint64_t values_end_offset = ufbxi_get_read_offset(uc) + values_len;
  7241. // Check if the values of the node we're parsing currently should be
  7242. // treated as an array.
  7243. ufbxi_array_info arr_info;
  7244. if (ufbxi_is_array_node(uc, parent_state, name, &arr_info)) {
  7245. // Normalize the array type (eg. 'r' to 'f'/'d' depending on the build)
  7246. // and get the per-element size of the array.
  7247. // Boolean arrays 'b' are normalized to 'c' as they are postprocessed
  7248. // below based on `arr_info.type`.
  7249. char dst_type = ufbxi_normalize_array_type(arr_info.type, 'c');
  7250. ufbxi_value_array *arr = ufbxi_push(tmp_buf, ufbxi_value_array, 1);
  7251. ufbxi_check(arr);
  7252. node->value_type_mask = UFBXI_VALUE_ARRAY;
  7253. node->array = arr;
  7254. arr->type = ufbxi_normalize_array_type(arr_info.type, 'b');
  7255. // Peek the first bytes of the array. We can always look at least 13 bytes
  7256. // ahead safely as valid FBX files must end in a 13/25 byte NULL record.
  7257. const char *data = ufbxi_peek_bytes(uc, 13);
  7258. ufbxi_check(data);
  7259. // Check if the data type is one of the explicit array types (post-7000).
  7260. // Otherwise we form the array by concatenating all the normal values of the
  7261. // node (pre-7000)
  7262. char c = data[0];
  7263. // HACK: Override the "type" if either the array is empty or we want to
  7264. // specifically ignore the contents.
  7265. if (num_values == 0) c = '0';
  7266. if (dst_type == '-') c = '-';
  7267. bool deferred = false;
  7268. if (c=='c' || c=='b' || c=='i' || c=='l' || c =='f' || c=='d') {
  7269. const char *arr_words = data + 1;
  7270. if (uc->file_big_endian) {
  7271. arr_words = ufbxi_swap_endian(uc, arr_words, 3, 4);
  7272. ufbxi_check(arr_words);
  7273. }
  7274. // Parse the array header from the prefix we already peeked above.
  7275. char src_type = data[0];
  7276. uint32_t size = ufbxi_read_u32(arr_words + 0);
  7277. uint32_t encoding = ufbxi_read_u32(arr_words + 4);
  7278. uint32_t encoded_size = ufbxi_read_u32(arr_words + 8);
  7279. ufbxi_consume_bytes(uc, 13);
  7280. // Normalize the source type as well, but don't convert UFBX-specific
  7281. // 'r' to 'f'/'d', but fail later instead.
  7282. if (src_type != 'r') src_type = ufbxi_normalize_array_type(src_type, 'c');
  7283. size_t src_elem_size = ufbxi_array_type_size(src_type);
  7284. size_t decoded_data_size = src_elem_size * size;
  7285. // Allocate `size` elements for the array.
  7286. char *arr_data = (char*)ufbxi_push_array_data(uc, &arr_info, size, tmp_buf);
  7287. ufbxi_check(arr_data);
  7288. uint64_t arr_begin = ufbxi_get_read_offset(uc);
  7289. ufbxi_check(UINT64_MAX - encoded_size > arr_begin);
  7290. uint64_t arr_end = arr_begin + encoded_size;
  7291. if (arr_end > uc->progress_bytes_total) {
  7292. uc->progress_bytes_total = arr_end;
  7293. }
  7294. // Threading
  7295. if (uc->parse_threaded && encoding == 1 && encoded_size >= UFBXI_MIN_THREADED_DEFLATE_BYTES && !uc->file_big_endian && !uc->local_big_endian) {
  7296. ufbxi_task *task = ufbxi_thread_pool_create_task(&uc->thread_pool, &ufbxi_deflate_task_fn);
  7297. if (task) {
  7298. ufbxi_deflate_task *t = ufbxi_push_zero(tmp_buf, ufbxi_deflate_task, 1);
  7299. ufbxi_check(t);
  7300. ufbxi_inflate_init_retain(uc->inflate_retain);
  7301. t->src_elem_size = src_elem_size;
  7302. t->encoded_size = encoded_size;
  7303. t->array_size = size;
  7304. t->src_type = src_type;
  7305. t->dst_type = dst_type;
  7306. t->arr_type = arr->type;
  7307. t->dst_data = arr_data;
  7308. t->inflate_retain = uc->inflate_retain;
  7309. if (!uc->read_fn) {
  7310. // From memory, no need to copy
  7311. t->encoded_data = uc->data;
  7312. } else {
  7313. void *encoded_data = ufbxi_push(tmp_buf, char, encoded_size);
  7314. ufbxi_check(encoded_data);
  7315. ufbxi_check(ufbxi_read_to(uc, encoded_data, encoded_size));
  7316. t->encoded_data = encoded_data;
  7317. }
  7318. if (src_type != dst_type) {
  7319. t->decoded_data = ufbxi_push_size(tmp_buf, src_elem_size, size);
  7320. ufbxi_check(t->decoded_data);
  7321. } else {
  7322. t->decoded_data = arr_data;
  7323. }
  7324. task->data = t;
  7325. ufbxi_thread_pool_run_task(&uc->thread_pool, task);
  7326. deferred = true;
  7327. }
  7328. }
  7329. // If the source and destination types are equal and our build is binary-compatible
  7330. // with the FBX format we can read the decoded data directly into the array buffer.
  7331. // Otherwise we need a temporary buffer to decode the array into before conversion.
  7332. void *decoded_data = arr_data;
  7333. if (!deferred && (src_type != dst_type || uc->local_big_endian != uc->file_big_endian)) {
  7334. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, decoded_data_size));
  7335. decoded_data = uc->tmp_arr;
  7336. }
  7337. if (deferred) {
  7338. // Nop
  7339. } else if (encoding == 0) {
  7340. // Encoding 0: Plain binary data.
  7341. ufbxi_check(encoded_size == decoded_data_size);
  7342. // If the array is contained in the current read buffer and we need to convert
  7343. // the data anyway we can use the read buffer as the decoded array source, otherwise
  7344. // do a plain byte copy to the array/conversion buffer.
  7345. if (uc->yield_size + uc->data_size >= encoded_size && decoded_data != arr_data) {
  7346. // Yield right after this if we crossed the yield threshold
  7347. if (encoded_size > uc->yield_size) {
  7348. uc->data_size += uc->yield_size;
  7349. uc->yield_size = encoded_size;
  7350. uc->data_size -= uc->yield_size;
  7351. }
  7352. decoded_data = (void*)uc->data;
  7353. ufbxi_consume_bytes(uc, encoded_size);
  7354. } else {
  7355. ufbxi_check(ufbxi_read_to(uc, decoded_data, encoded_size));
  7356. }
  7357. } else if (encoding == 1) {
  7358. // Encoding 1: DEFLATE
  7359. ufbxi_pause_progress(uc);
  7360. // Inflate the data from the user-provided IO buffer / read callbacks
  7361. ufbx_inflate_input input;
  7362. input.total_size = encoded_size;
  7363. input.data = uc->data;
  7364. input.data_size = uc->data_size;
  7365. input.no_header = false;
  7366. input.no_checksum = false;
  7367. input.internal_fast_bits = 0;
  7368. if (uc->opts.progress_cb.fn) {
  7369. input.progress_cb = uc->opts.progress_cb;
  7370. input.progress_size_before = arr_begin;
  7371. input.progress_size_after = uc->progress_bytes_total - arr_end;
  7372. input.progress_interval_hint = uc->progress_interval;
  7373. } else {
  7374. input.progress_cb.fn = NULL;
  7375. input.progress_cb.user = NULL;
  7376. input.progress_size_before = 0;
  7377. input.progress_size_after = 0;
  7378. input.progress_interval_hint = 0;
  7379. }
  7380. // If the encoded array is larger than the data we have currently buffered
  7381. // we need to allow `ufbx_inflate()` to read from the IO callback. We can
  7382. // let `ufbx_inflate()` freely clobber our `read_buffer` as all the data
  7383. // in the buffer will be consumed. `ufbx_inflate()` always reads exactly
  7384. // the amount of bytes needed so we can continue reading from `read_fn` as
  7385. // usual (given that we clear the `uc->data/_size` buffer below).
  7386. // NOTE: We _cannot_ share `read_buffer` if we plan to read later from it
  7387. // as `ufbx_inflate()` overwrites parts of it with zeroes.
  7388. if (encoded_size > input.data_size) {
  7389. input.buffer = uc->read_buffer;
  7390. input.buffer_size = uc->read_buffer_size;
  7391. input.read_fn = uc->read_fn;
  7392. input.read_user = uc->read_user;
  7393. uc->data_offset += encoded_size - input.data_size;
  7394. uc->data += input.data_size;
  7395. uc->data_size = 0;
  7396. } else {
  7397. input.buffer = NULL;
  7398. input.buffer_size = 0;
  7399. input.read_fn = NULL;
  7400. input.read_user = NULL;
  7401. uc->data += encoded_size;
  7402. uc->data_size -= encoded_size;
  7403. ufbxi_check(ufbxi_resume_progress(uc));
  7404. }
  7405. ptrdiff_t res = ufbx_inflate(decoded_data, decoded_data_size, &input, uc->inflate_retain);
  7406. ufbxi_check_msg(res != -28, "Cancelled");
  7407. ufbxi_check_msg(res == (ptrdiff_t)decoded_data_size, "Bad DEFLATE data");
  7408. } else {
  7409. ufbxi_fail("Bad array encoding");
  7410. }
  7411. // Convert the decoded array if necessary.
  7412. if (!deferred && decoded_data != arr_data) {
  7413. ufbxi_check(ufbxi_binary_convert_array(uc, src_type, dst_type, decoded_data, arr_data, size));
  7414. }
  7415. arr->data = arr_data;
  7416. arr->size = size;
  7417. } else if (c == '0' || c == '-') {
  7418. // Ignore the array
  7419. arr->type = c == '-' ? '-' : dst_type;
  7420. arr->data = (char*)ufbxi_zero_size_buffer + 32;
  7421. arr->size = 0;
  7422. } else {
  7423. // Allocate `num_values` elements for the array and parse single values into it.
  7424. char *arr_data = (char*)ufbxi_push_array_data(uc, &arr_info, num_values, tmp_buf);
  7425. ufbxi_check(arr_data);
  7426. ufbxi_check(ufbxi_binary_parse_multivalue_array(uc, dst_type, arr_data, num_values, tmp_buf));
  7427. arr->data = arr_data;
  7428. arr->size = num_values;
  7429. }
  7430. // Post-process boolean arrays
  7431. if (!deferred && arr_info.type == 'b') {
  7432. ufbxi_postprocess_bool_array((char*)arr->data, arr->size);
  7433. }
  7434. } else {
  7435. // Parse up to UFBXI_MAX_NON_ARRAY_VALUES as plain values
  7436. num_values = ufbxi_min32(num_values, UFBXI_MAX_NON_ARRAY_VALUES);
  7437. ufbxi_value *vals = ufbxi_push(tmp_buf, ufbxi_value, num_values);
  7438. ufbxi_check(vals);
  7439. node->vals = vals;
  7440. uint32_t type_mask = 0;
  7441. for (size_t i = 0; i < (size_t)num_values; i++) {
  7442. // The file must end in a 13/25 byte NULL record, so we can peek
  7443. // up to 13 bytes safely here.
  7444. const char *data = ufbxi_peek_bytes(uc, 13);
  7445. ufbxi_check(data);
  7446. const char *value = data + 1;
  7447. char type = data[0];
  7448. if (uc->file_big_endian) {
  7449. value = ufbxi_swap_endian_value(uc, value, type);
  7450. ufbxi_check(value);
  7451. }
  7452. switch (type) {
  7453. case 'C': case 'B': case 'Z':
  7454. type_mask |= (uint32_t)UFBXI_VALUE_NUMBER << (i*2);
  7455. vals[i].f = (double)(vals[i].i = (int64_t)(uint8_t)value[0]);
  7456. ufbxi_consume_bytes(uc, 2);
  7457. break;
  7458. case 'Y':
  7459. type_mask |= (uint32_t)UFBXI_VALUE_NUMBER << (i*2);
  7460. vals[i].f = (double)(vals[i].i = ufbxi_read_i16(value));
  7461. ufbxi_consume_bytes(uc, 3);
  7462. break;
  7463. case 'I':
  7464. type_mask |= (uint32_t)UFBXI_VALUE_NUMBER << (i*2);
  7465. vals[i].f = (double)(vals[i].i = ufbxi_read_i32(value));
  7466. ufbxi_consume_bytes(uc, 5);
  7467. break;
  7468. case 'L':
  7469. type_mask |= (uint32_t)UFBXI_VALUE_NUMBER << (i*2);
  7470. vals[i].f = (double)(vals[i].i = ufbxi_read_i64(value));
  7471. ufbxi_consume_bytes(uc, 9);
  7472. break;
  7473. case 'F':
  7474. type_mask |= (uint32_t)UFBXI_VALUE_NUMBER << (i*2);
  7475. vals[i].i = ufbxi_f64_to_i64(vals[i].f = ufbxi_read_f32(value));
  7476. ufbxi_consume_bytes(uc, 5);
  7477. break;
  7478. case 'D':
  7479. type_mask |= (uint32_t)UFBXI_VALUE_NUMBER << (i*2);
  7480. vals[i].i = ufbxi_f64_to_i64(vals[i].f = ufbxi_read_f64(value));
  7481. ufbxi_consume_bytes(uc, 9);
  7482. break;
  7483. case 'S': case 'R':
  7484. {
  7485. uint32_t length = ufbxi_read_u32(value);
  7486. ufbxi_consume_bytes(uc, 5);
  7487. const char *str = ufbxi_read_bytes(uc, length);
  7488. ufbxi_check(str);
  7489. if (length == 0) {
  7490. vals[i].s.raw_data = ufbxi_empty_char;
  7491. vals[i].s.raw_length = 0;
  7492. vals[i].s.utf8_length = 0;
  7493. } else {
  7494. bool non_ascii = false;
  7495. uint32_t hash = ufbxi_hash_string_check_ascii(str, length, &non_ascii);
  7496. bool raw = !non_ascii || ufbxi_is_raw_string(uc, parent_state, name, i);
  7497. ufbxi_check(ufbxi_push_sanitized_string(&uc->string_pool, &vals[i].s, str, length, hash, raw));
  7498. // Mark the data as invalid UTF-8
  7499. if (non_ascii && raw) vals[i].s.utf8_length = UINT32_MAX;
  7500. }
  7501. type_mask |= (uint32_t)UFBXI_VALUE_STRING << (i*2);
  7502. }
  7503. break;
  7504. // Treat arrays as non-values and skip them
  7505. case 'c': case 'b': case 'i': case 'l': case 'f': case 'd':
  7506. {
  7507. uint32_t encoded_size = ufbxi_read_u32(value + 8);
  7508. ufbxi_consume_bytes(uc, 13);
  7509. ufbxi_check(ufbxi_skip_bytes(uc, encoded_size));
  7510. }
  7511. break;
  7512. default:
  7513. ufbxi_fail("Bad value type");
  7514. }
  7515. }
  7516. node->value_type_mask = (uint16_t)type_mask;
  7517. }
  7518. // Skip over remaining values if necessary if we for example truncated
  7519. // the list of values or if there are values after an array
  7520. uint64_t offset = ufbxi_get_read_offset(uc);
  7521. ufbxi_check(offset <= values_end_offset);
  7522. if (offset < values_end_offset) {
  7523. ufbxi_check(ufbxi_skip_bytes(uc, values_end_offset - offset));
  7524. }
  7525. if (recursive) {
  7526. // Recursively parse the children of this node. Update the parse state
  7527. // to provide context for child node parsing.
  7528. ufbxi_parse_state parse_state = ufbxi_update_parse_state(parent_state, node->name);
  7529. uint32_t num_children = 0;
  7530. for (;;) {
  7531. // Stop at end offset
  7532. uint64_t current_offset = ufbxi_get_read_offset(uc);
  7533. if (current_offset >= end_offset) {
  7534. ufbxi_check(current_offset == end_offset || end_offset == 0);
  7535. break;
  7536. }
  7537. bool end = false;
  7538. ufbxi_check(ufbxi_binary_parse_node(uc, depth + 1, parse_state, &end, tmp_buf, true));
  7539. if (end) break;
  7540. num_children++;
  7541. }
  7542. // Pop children from `tmp_stack` to a contiguous array
  7543. node->num_children = num_children;
  7544. if (num_children > 0) {
  7545. node->children = ufbxi_push_pop(tmp_buf, &uc->tmp_stack, ufbxi_node, num_children);
  7546. ufbxi_check(node->children);
  7547. }
  7548. } else {
  7549. uint64_t current_offset = ufbxi_get_read_offset(uc);
  7550. uc->has_next_child = (current_offset < end_offset);
  7551. }
  7552. return 1;
  7553. }
  7554. #define UFBXI_BINARY_MAGIC_SIZE 22
  7555. #define UFBXI_BINARY_HEADER_SIZE 27
  7556. static const char ufbxi_binary_magic[] = "Kaydara FBX Binary \x00\x1a";
  7557. // -- ASCII parsing
  7558. #define UFBXI_ASCII_END '\0'
  7559. #define UFBXI_ASCII_NAME 'N'
  7560. #define UFBXI_ASCII_BARE_WORD 'B'
  7561. #define UFBXI_ASCII_INT 'I'
  7562. #define UFBXI_ASCII_FLOAT 'F'
  7563. #define UFBXI_ASCII_STRING 'S'
  7564. static ufbxi_noinline char ufbxi_ascii_refill(ufbxi_context *uc)
  7565. {
  7566. ufbxi_ascii *ua = &uc->ascii;
  7567. uc->data_offset += ufbxi_to_size(ua->src - uc->data_begin);
  7568. if (uc->read_fn) {
  7569. char *dst_buffer = NULL;
  7570. size_t dst_size = 0;
  7571. if (ua->retain_buf != NULL) {
  7572. dst_size = uc->opts.read_buffer_size;
  7573. dst_buffer = ufbxi_push(ua->retain_buf, char, dst_size);
  7574. ufbxi_check_return(dst_buffer, '\0');
  7575. ua->src_is_retained = true;
  7576. ua->src_buf = ua->retain_buf;
  7577. } else {
  7578. // Grow the read buffer if necessary
  7579. if (uc->read_buffer_size < uc->opts.read_buffer_size) {
  7580. size_t new_size = uc->opts.read_buffer_size;
  7581. ufbxi_check_return(ufbxi_grow_array(&uc->ator_tmp, &uc->read_buffer, &uc->read_buffer_size, new_size), '\0');
  7582. }
  7583. dst_buffer = uc->read_buffer;
  7584. dst_size = uc->read_buffer_size;
  7585. ua->src_is_retained = false;
  7586. ua->src_buf = NULL;
  7587. }
  7588. // Read user data, return '\0' on EOF
  7589. // TODO: Very unoptimal for non-full-size reads in some cases
  7590. size_t num_read = uc->read_fn(uc->read_user, dst_buffer, dst_size);
  7591. ufbxi_check_return_msg(num_read != SIZE_MAX, '\0', "IO error");
  7592. ufbxi_check_return(num_read <= uc->read_buffer_size, '\0');
  7593. if (num_read == 0) return '\0';
  7594. uc->data = uc->data_begin = ua->src = dst_buffer;
  7595. ua->src_end = dst_buffer + num_read;
  7596. return *ua->src;
  7597. } else {
  7598. // If the user didn't specify a `read_fn()` treat anything
  7599. // past the initial data buffer as EOF.
  7600. uc->data = uc->data_begin = ua->src = "";
  7601. ua->src_end = ua->src + 1;
  7602. return '\0';
  7603. }
  7604. }
  7605. static ufbxi_noinline char ufbxi_ascii_yield(ufbxi_context *uc)
  7606. {
  7607. ufbxi_ascii *ua = &uc->ascii;
  7608. char ret;
  7609. if (ua->src == ua->src_end) {
  7610. ret = ufbxi_ascii_refill(uc);
  7611. } else {
  7612. ret = *ua->src;
  7613. }
  7614. if (ufbxi_to_size(ua->src_end - ua->src) < uc->progress_interval) {
  7615. ua->src_yield = ua->src_end;
  7616. } else {
  7617. ua->src_yield = ua->src + uc->progress_interval;
  7618. }
  7619. // TODO: Unify these properly
  7620. uc->data = ua->src;
  7621. ufbxi_check_return(ufbxi_report_progress(uc), '\0');
  7622. return ret;
  7623. }
  7624. static ufbxi_forceinline char ufbxi_ascii_peek(ufbxi_context *uc)
  7625. {
  7626. ufbxi_ascii *ua = &uc->ascii;
  7627. if (ua->src == ua->src_yield) return ufbxi_ascii_yield(uc);
  7628. return *ua->src;
  7629. }
  7630. static ufbxi_forceinline char ufbxi_ascii_next(ufbxi_context *uc)
  7631. {
  7632. ufbxi_ascii *ua = &uc->ascii;
  7633. if (ua->src == ua->src_yield) return ufbxi_ascii_yield(uc);
  7634. ua->src++;
  7635. if (ua->src == ua->src_yield) return ufbxi_ascii_yield(uc);
  7636. return *ua->src;
  7637. }
  7638. static ufbxi_noinline uint32_t ufbxi_ascii_parse_version(ufbxi_context *uc)
  7639. {
  7640. uint8_t digits[3];
  7641. uint32_t num_digits = 0;
  7642. char c = ufbxi_ascii_next(uc);
  7643. const char fmt[] = " FBX ?.?.?";
  7644. uint32_t ix = 0;
  7645. while (num_digits < 3) {
  7646. char ref = fmt[ix++];
  7647. switch (ref) {
  7648. // Digit
  7649. case '?':
  7650. if (c < '0' || c > '9') return 0;
  7651. digits[num_digits++] = (uint8_t)(c - '0');
  7652. c = ufbxi_ascii_next(uc);
  7653. break;
  7654. // Whitespace
  7655. case ' ':
  7656. while (c == ' ' || c == '\t') {
  7657. c = ufbxi_ascii_next(uc);
  7658. }
  7659. break;
  7660. // Literal character
  7661. default:
  7662. if (c != ref) return 0;
  7663. c = ufbxi_ascii_next(uc);
  7664. break;
  7665. }
  7666. }
  7667. if (num_digits != 3) return 0;
  7668. return 1000u*(uint32_t)digits[0] + 100u*(uint32_t)digits[1] + 10u*(uint32_t)digits[2];
  7669. }
  7670. static const uint32_t ufbxi_space_mask =
  7671. (1u << ((uint32_t)' ' - 1)) |
  7672. (1u << ((uint32_t)'\t' - 1)) |
  7673. (1u << ((uint32_t)'\r' - 1)) |
  7674. (1u << ((uint32_t)'\n' - 1)) ;
  7675. ufbx_static_assert(space_codepoint,
  7676. (uint32_t)' ' <= 32u && (uint32_t)'\t' <= 32u &&
  7677. (uint32_t)'\r' <= 32u && (uint32_t)'\n' <= 32u);
  7678. static ufbxi_forceinline bool ufbxi_is_space(char c)
  7679. {
  7680. uint32_t v = (uint32_t)(uint8_t)c - 1;
  7681. return v < 32 && ((ufbxi_space_mask >> v) & 0x1) != 0;
  7682. }
  7683. static ufbxi_noinline char ufbxi_ascii_skip_whitespace(ufbxi_context *uc)
  7684. {
  7685. ufbxi_ascii *ua = &uc->ascii;
  7686. // Ignore whitespace
  7687. char c = ufbxi_ascii_peek(uc);
  7688. for (;;) {
  7689. while (ufbxi_is_space(c)) {
  7690. c = ufbxi_ascii_next(uc);
  7691. }
  7692. // Line comment
  7693. if (c == ';') {
  7694. bool read_magic = false;
  7695. // FBX ASCII files begin with a magic comment of form "; FBX 7.7.0 project file"
  7696. // Try to extract the version number from the magic comment
  7697. if (!ua->read_first_comment) {
  7698. ua->read_first_comment = true;
  7699. uint32_t version = ufbxi_ascii_parse_version(uc);
  7700. if (version) {
  7701. uc->version = version;
  7702. ua->found_version = true;
  7703. read_magic = true;
  7704. }
  7705. }
  7706. c = ufbxi_ascii_next(uc);
  7707. while (c != '\n' && c != '\0') {
  7708. c = ufbxi_ascii_next(uc);
  7709. }
  7710. c = ufbxi_ascii_next(uc);
  7711. // Try to determine if this is a Blender 6100 ASCII file
  7712. if (read_magic) {
  7713. if (c == ';') {
  7714. char line[32];
  7715. size_t line_len = 0;
  7716. c = ufbxi_ascii_next(uc);
  7717. while (c != '\n' && c != '\0') {
  7718. if (line_len < sizeof(line)) {
  7719. line[line_len++] = c;
  7720. }
  7721. c = ufbxi_ascii_next(uc);
  7722. }
  7723. if (line_len >= 19 && !memcmp(line, " Created by Blender", 19)) {
  7724. uc->exporter = UFBX_EXPORTER_BLENDER_ASCII;
  7725. }
  7726. }
  7727. }
  7728. } else {
  7729. break;
  7730. }
  7731. }
  7732. return c;
  7733. }
  7734. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_ascii_push_token_char(ufbxi_context *uc, ufbxi_ascii_token *token, char c)
  7735. {
  7736. // Grow the string data buffer if necessary
  7737. if (token->str_len == token->str_cap) {
  7738. size_t len = ufbxi_max_sz(token->str_len + 1, 256);
  7739. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &token->str_data, &token->str_cap, len));
  7740. }
  7741. token->str_data[token->str_len++] = c;
  7742. return 1;
  7743. }
  7744. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_ascii_push_token_string(ufbxi_context *uc, ufbxi_ascii_token *token, const char *data, size_t length)
  7745. {
  7746. // Grow the string data buffer if necessary
  7747. if (token->str_len + length >= token->str_cap) {
  7748. size_t len = ufbxi_max_sz(token->str_len + length, 256);
  7749. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &token->str_data, &token->str_cap, len));
  7750. }
  7751. memcpy(token->str_data + token->str_len, data, length);
  7752. token->str_len += length;
  7753. return 1;
  7754. }
  7755. ufbxi_nodiscard ufbxi_noinline static int ufbxi_ascii_skip_until(ufbxi_context *uc, char dst)
  7756. {
  7757. ufbxi_ascii *ua = &uc->ascii;
  7758. for (;;) {
  7759. size_t buffered = ufbxi_to_size(ua->src_yield - ua->src);
  7760. const char *match = (const char*)memchr(ua->src, dst, buffered);
  7761. if (match) {
  7762. ua->src = match;
  7763. break;
  7764. } else {
  7765. ua->src += buffered;
  7766. }
  7767. if (buffered == 0) {
  7768. char c = ufbxi_ascii_yield(uc);
  7769. ufbxi_check(c != '\0');
  7770. }
  7771. }
  7772. return 1;
  7773. }
  7774. typedef struct {
  7775. const char *source;
  7776. size_t length;
  7777. } ufbxi_ascii_span;
  7778. ufbxi_nodiscard ufbxi_noinline static int ufbxi_ascii_store_array(ufbxi_context *uc, ufbxi_buf *tmp_buf)
  7779. {
  7780. ufbxi_ascii *ua = &uc->ascii;
  7781. ua->retain_buf = tmp_buf;
  7782. for (;;) {
  7783. size_t buffered = ufbxi_to_size(ua->src_yield - ua->src);
  7784. if (buffered == 0) {
  7785. char c = ufbxi_ascii_yield(uc);
  7786. ufbxi_check(c != '\0');
  7787. continue;
  7788. }
  7789. const char *begin = ua->src, *end;
  7790. const char *match = (const char*)memchr(begin, '}', buffered);
  7791. if (match) {
  7792. end = match;
  7793. } else {
  7794. end = begin + buffered;
  7795. }
  7796. ua->src = end;
  7797. size_t length = ufbxi_to_size(end - begin);
  7798. ufbxi_ascii_span *span = ufbxi_push(&uc->tmp_ascii_spans, ufbxi_ascii_span, 1);
  7799. ufbxi_check(span);
  7800. // Store the trailing '}' for parsing
  7801. if (match) length += 1;
  7802. span->length = length;
  7803. if (ua->src_is_retained || !uc->read_fn) {
  7804. span->source = begin;
  7805. } else {
  7806. span->source = ufbxi_push_copy(tmp_buf, char, length, begin);
  7807. ufbxi_check(span->source);
  7808. }
  7809. if (match) break;
  7810. }
  7811. ua->retain_buf = NULL;
  7812. return 1;
  7813. }
  7814. ufbxi_nodiscard ufbxi_noinline static int ufbxi_ascii_try_ignore_string(ufbxi_context *uc, ufbxi_ascii_token *token)
  7815. {
  7816. ufbxi_ascii *ua = &uc->ascii;
  7817. char c = ufbxi_ascii_skip_whitespace(uc);
  7818. token->str_len = 0;
  7819. if (c == '"') {
  7820. // Replace `prev_token` with `token` but swap the buffers so `token` uses
  7821. // the now-unused string buffer of the old `prev_token`.
  7822. char *swap_data = ua->prev_token.str_data;
  7823. size_t swap_cap = ua->prev_token.str_cap;
  7824. ua->prev_token = ua->token;
  7825. ua->token.str_data = swap_data;
  7826. ua->token.str_cap = swap_cap;
  7827. token->type = UFBXI_ASCII_STRING;
  7828. // Skip opening quote
  7829. ufbxi_ascii_next(uc);
  7830. ufbxi_check(ufbxi_ascii_skip_until(uc, '"'));
  7831. // Skip closing quote
  7832. ufbxi_ascii_next(uc);
  7833. return true;
  7834. }
  7835. return false;
  7836. }
  7837. ufbxi_nodiscard ufbxi_noinline static int ufbxi_ascii_next_token(ufbxi_context *uc, ufbxi_ascii_token *token)
  7838. {
  7839. ufbxi_ascii *ua = &uc->ascii;
  7840. // Replace `prev_token` with `token` but swap the buffers so `token` uses
  7841. // the now-unused string buffer of the old `prev_token`.
  7842. char *swap_data = ua->prev_token.str_data;
  7843. size_t swap_cap = ua->prev_token.str_cap;
  7844. ua->prev_token = ua->token;
  7845. ua->token.str_data = swap_data;
  7846. ua->token.str_cap = swap_cap;
  7847. char c = ufbxi_ascii_skip_whitespace(uc);
  7848. token->str_len = 0;
  7849. if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c == '_') {
  7850. token->type = UFBXI_ASCII_BARE_WORD;
  7851. while ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')
  7852. || (c >= '0' && c <= '9') || c == '_') {
  7853. ufbxi_check(ufbxi_ascii_push_token_char(uc, token, c));
  7854. c = ufbxi_ascii_next(uc);
  7855. }
  7856. // Skip whitespace to find if there's a following ':'
  7857. c = ufbxi_ascii_skip_whitespace(uc);
  7858. if (c == ':') {
  7859. token->value.name_len = token->str_len;
  7860. token->type = UFBXI_ASCII_NAME;
  7861. ufbxi_ascii_next(uc);
  7862. }
  7863. } else if ((c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.') {
  7864. token->type = UFBXI_ASCII_INT;
  7865. token->negative = c == '-';
  7866. while ((c >= '0' && c <= '9') || c == '-' || c == '+' || c == '.' || c == 'e' || c == 'E') {
  7867. if (c == '.' || c == 'e' || c == 'E') {
  7868. token->type = UFBXI_ASCII_FLOAT;
  7869. }
  7870. ufbxi_check(ufbxi_ascii_push_token_char(uc, token, c));
  7871. c = ufbxi_ascii_next(uc);
  7872. }
  7873. if (c == '#') {
  7874. ufbxi_check(token->type == UFBXI_ASCII_FLOAT);
  7875. ufbxi_check(ufbxi_ascii_push_token_char(uc, token, c));
  7876. c = ufbxi_ascii_next(uc);
  7877. bool is_inf = c == 'I' || c == 'i';
  7878. while ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
  7879. ufbxi_check(ufbxi_ascii_push_token_char(uc, token, c));
  7880. c = ufbxi_ascii_next(uc);
  7881. }
  7882. ufbxi_check(ufbxi_ascii_push_token_char(uc, token, '\0'));
  7883. if (is_inf) {
  7884. token->value.f64 = token->str_data[0] == '-' ? -UFBX_INFINITY : UFBX_INFINITY;
  7885. } else {
  7886. token->value.f64 = UFBX_NAN;
  7887. }
  7888. } else {
  7889. ufbxi_check(ufbxi_ascii_push_token_char(uc, token, '\0'));
  7890. char *end;
  7891. if (token->type == UFBXI_ASCII_INT) {
  7892. token->value.i64 = ufbxi_parse_int64(token->str_data, &end);
  7893. ufbxi_check(end == token->str_data + token->str_len - 1);
  7894. } else if (token->type == UFBXI_ASCII_FLOAT) {
  7895. if (ua->parse_as_f32) {
  7896. token->value.f64 = strtof(token->str_data, &end);
  7897. } else {
  7898. token->value.f64 = ufbxi_parse_double(token->str_data, token->str_len, &end, uc->double_parse_flags);
  7899. }
  7900. ufbxi_check(end == token->str_data + token->str_len - 1);
  7901. }
  7902. }
  7903. } else if (c == '"') {
  7904. token->type = UFBXI_ASCII_STRING;
  7905. c = ufbxi_ascii_next(uc);
  7906. while (c != '"') {
  7907. // Optimized string parsing for non-special characters
  7908. if (ua->src + 1 < ua->src_yield) {
  7909. const char *begin = ua->src;
  7910. const char *end = ua->src_yield;
  7911. const char *quot = (const char*)memchr(begin, '"', ufbxi_to_size(end - begin));
  7912. if (quot) end = quot;
  7913. const char *esc = (const char*)memchr(begin, '&', ufbxi_to_size(end - begin));
  7914. if (esc) end = esc;
  7915. if (begin < end) {
  7916. ufbxi_check(ufbxi_ascii_push_token_string(uc, token, begin, ufbxi_to_size(end - begin)));
  7917. ua->src = end;
  7918. c = ufbxi_ascii_peek(uc);
  7919. continue;
  7920. }
  7921. }
  7922. // Escape XML-like elements, funny enough there is no way to escape '&' itself, there is no `&amp`.
  7923. // '&quot;' -> '"'
  7924. // '&cr;' -> '\r'
  7925. // '&lf;' -> '\n'
  7926. if (c == '&') {
  7927. const char *entity = NULL;
  7928. char replacement = '\0';
  7929. c = ufbxi_ascii_next(uc);
  7930. switch (c) {
  7931. case 'q':
  7932. entity = "&quot;";
  7933. replacement = '"';
  7934. break;
  7935. case 'c':
  7936. entity = "&cr;";
  7937. replacement = '\r';
  7938. break;
  7939. case 'l':
  7940. entity = "&lf;";
  7941. replacement = '\n';
  7942. break;
  7943. default:
  7944. // As '&' is not escaped in any way just map '&' -> '&'
  7945. entity = "&";
  7946. replacement = '&';
  7947. break;
  7948. }
  7949. size_t step = 1;
  7950. ufbxi_dev_assert(entity && *entity);
  7951. // `entity` is a NULL terminated string longer than a single character
  7952. // cppcheck-suppress arrayIndexOutOfBounds
  7953. for (; entity[step]; step++) {
  7954. if (c != entity[step]) break;
  7955. c = ufbxi_ascii_next(uc);
  7956. }
  7957. if (entity[step] == '\0') {
  7958. // Full match: Push the replacement character
  7959. ufbxi_check(ufbxi_ascii_push_token_char(uc, token, replacement));
  7960. } else {
  7961. // Partial match: Push the prefix we have skipped already
  7962. for (size_t i = 0; i < step; i++) {
  7963. ufbxi_check(ufbxi_ascii_push_token_char(uc, token, entity[i]));
  7964. }
  7965. }
  7966. continue;
  7967. }
  7968. ufbxi_check(c != '\0');
  7969. ufbxi_check(ufbxi_ascii_push_token_char(uc, token, c));
  7970. c = ufbxi_ascii_next(uc);
  7971. }
  7972. // Skip closing quote
  7973. ufbxi_ascii_next(uc);
  7974. } else {
  7975. // Single character token
  7976. token->type = c;
  7977. ufbxi_ascii_next(uc);
  7978. }
  7979. return 1;
  7980. }
  7981. ufbxi_nodiscard static int ufbxi_ascii_accept(ufbxi_context *uc, char type)
  7982. {
  7983. ufbxi_ascii *ua = &uc->ascii;
  7984. if (ua->token.type == type) {
  7985. ufbxi_check(ufbxi_ascii_next_token(uc, &ua->token));
  7986. return 1;
  7987. } else {
  7988. return 0;
  7989. }
  7990. }
  7991. ufbxi_nodiscard static ufbxi_noinline int ufbxi_ascii_read_int_array(ufbxi_context *uc, char type, size_t *p_num_read)
  7992. {
  7993. ufbxi_ascii *ua = &uc->ascii;
  7994. if (ua->parse_as_f32) return 1;
  7995. size_t initial_items = uc->tmp_stack.num_items;
  7996. int64_t val;
  7997. if (ua->token.type == UFBXI_ASCII_INT) {
  7998. val = ua->token.value.i64;
  7999. } else {
  8000. return 1;
  8001. }
  8002. const char *src = ua->src;
  8003. const char *end = ua->src_yield;
  8004. const char *src_scan = src;
  8005. for (;;) {
  8006. // Skip '\s*,\s*' between array elements. If we don't find a comma after an element
  8007. // don't push it as we can't be 100% certain whether it's a part of the array.
  8008. while (src_scan != end && ufbxi_is_space(*src_scan)) src_scan++;
  8009. if (src_scan == end || *src_scan != ',') break;
  8010. src_scan++;
  8011. while (src_scan != end && ufbxi_is_space(*src_scan)) src_scan++;
  8012. // Found comma, commit to the position and push the previous value to the array
  8013. src = src_scan;
  8014. if (type == 'i') {
  8015. int32_t *v = ufbxi_push_fast(&uc->tmp_stack, int32_t, 1);
  8016. ufbxi_check(v);
  8017. *v = (int32_t)val;
  8018. } else if (type == 'l') {
  8019. int64_t *v = ufbxi_push_fast(&uc->tmp_stack, int64_t, 1);
  8020. ufbxi_check(v);
  8021. *v = (int64_t)val;
  8022. }
  8023. // Try to parse the next value, we don't commit this until we find a comma after it above.
  8024. size_t left = ufbxi_to_size(end - src_scan);
  8025. if (left < 32) break;
  8026. val = ufbxi_parse_int64(src_scan, (char**)&src_scan);
  8027. if (!src_scan) break;
  8028. }
  8029. // Resume conventional parsing if we moved `src`.
  8030. if (src != ua->src) {
  8031. ua->src = src;
  8032. ufbxi_check(ufbxi_ascii_next_token(uc, &ua->token));
  8033. }
  8034. *p_num_read = uc->tmp_stack.num_items - initial_items;
  8035. return 1;
  8036. }
  8037. typedef struct {
  8038. void *arr_data;
  8039. char arr_type;
  8040. size_t arr_size;
  8041. const ufbxi_ascii_span *spans;
  8042. size_t num_spans;
  8043. size_t offset;
  8044. } ufbxi_ascii_array_task;
  8045. ufbxi_noinline static const char *ufbxi_ascii_array_task_parse_floats(ufbxi_ascii_array_task *t, const char *src, const char *src_end, uint32_t parse_flags)
  8046. {
  8047. size_t offset = t->offset;
  8048. float *dst_float = t->arr_type == 'f' ? (float*)t->arr_data + offset : NULL;
  8049. double *dst_double = t->arr_type == 'd' ? (double*)t->arr_data + offset : NULL;
  8050. ufbx_assert(dst_float || dst_double);
  8051. const char *src_begin = src;
  8052. while (src != src_end) {
  8053. while (ufbxi_is_space(*src)) src++;
  8054. // Try to parse the next value, we don't commit this until we find a comma after it above.
  8055. char *num_end = NULL;
  8056. double val = ufbxi_parse_double(src, ufbxi_to_size(src_end - src), &num_end, parse_flags);
  8057. if (!num_end) return src_begin;
  8058. src = num_end;
  8059. while (ufbxi_is_space(*src)) src++;
  8060. if (*src != ',') break;
  8061. src++;
  8062. src_begin = src;
  8063. if (offset >= t->arr_size) return NULL;
  8064. if (dst_double) {
  8065. *dst_double++ = val;
  8066. } else {
  8067. *dst_float++ = (float)val;
  8068. }
  8069. offset++;
  8070. }
  8071. t->offset = offset;
  8072. return src_begin;
  8073. }
  8074. ufbxi_noinline static const char *ufbxi_ascii_array_task_parse_ints(ufbxi_ascii_array_task *t, const char *src, const char *src_end)
  8075. {
  8076. size_t offset = t->offset;
  8077. int32_t *dst32 = t->arr_type == 'i' ? (int32_t*)t->arr_data + offset : NULL;
  8078. int64_t *dst64 = t->arr_type == 'l' ? (int64_t*)t->arr_data + offset : NULL;
  8079. ufbx_assert(dst32 || dst64);
  8080. const char *src_begin = src;
  8081. while (src != src_end) {
  8082. while (ufbxi_is_space(*src)) src++;
  8083. int64_t val = ufbxi_parse_int64(src, (char**)&src);
  8084. if (!src) return NULL;
  8085. while (ufbxi_is_space(*src)) src++;
  8086. if (*src != ',') break;
  8087. src++;
  8088. src_begin = src;
  8089. if (offset >= t->arr_size) return NULL;
  8090. if (dst32) {
  8091. *dst32++ = (int32_t)val;
  8092. } else {
  8093. *dst64++ = val;
  8094. }
  8095. offset++;
  8096. }
  8097. t->offset = offset;
  8098. return src_begin;
  8099. }
  8100. ufbxi_noinline static const char *ufbxi_ascii_array_task_parse(ufbxi_ascii_array_task *t, const char *src, const char *src_end)
  8101. {
  8102. if (t->arr_type == 'f' || t->arr_type == 'd') {
  8103. uint32_t flags = ufbxi_parse_double_init_flags();
  8104. return ufbxi_ascii_array_task_parse_floats(t, src, src_end, flags);
  8105. } else {
  8106. return ufbxi_ascii_array_task_parse_ints(t, src, src_end);
  8107. }
  8108. }
  8109. typedef enum {
  8110. UFBXI_ASCII_SCAN_STATE_VALUE,
  8111. UFBXI_ASCII_SCAN_STATE_WHITESPACE,
  8112. UFBXI_ASCII_SCAN_STATE_COMMENT,
  8113. UFBXI_ASCII_SCAN_STATE_COMMA,
  8114. } ufbxi_ascii_scan_state;
  8115. ufbxi_noinline static bool ufbxi_ascii_array_task_imp(ufbxi_ascii_array_task *t)
  8116. {
  8117. // Temporary buffer for parsing between spans
  8118. char buffer[128]; // ufbxi_uninit
  8119. size_t buffer_len = 0;
  8120. bool buffer_value = false;
  8121. ufbxi_ascii_scan_state state = UFBXI_ASCII_SCAN_STATE_WHITESPACE;
  8122. ufbxi_for(const ufbxi_ascii_span, span, t->spans, t->num_spans) {
  8123. const char *src = span->source;
  8124. const char *end = src + span->length;
  8125. while (src != end) {
  8126. // State machine for skipping whitespace and comments, potentially
  8127. // between multiple spans.
  8128. while (src != end) {
  8129. char c = *src;
  8130. if (state == UFBXI_ASCII_SCAN_STATE_VALUE) {
  8131. if (buffer_len >= sizeof(buffer) - 1) return false;
  8132. if (c == '"') {
  8133. return false;
  8134. } else if (c == ';' || ufbxi_is_space(c)) {
  8135. state = UFBXI_ASCII_SCAN_STATE_WHITESPACE;
  8136. buffer[buffer_len] = ' ';
  8137. buffer_len++;
  8138. } else if (c == ',' || c == '}') {
  8139. state = UFBXI_ASCII_SCAN_STATE_COMMA;
  8140. buffer[buffer_len] = ',';
  8141. buffer_len++;
  8142. src++;
  8143. break;
  8144. } else {
  8145. buffer_value = true;
  8146. buffer[buffer_len] = c;
  8147. buffer_len++;
  8148. src++;
  8149. }
  8150. } else if (state == UFBXI_ASCII_SCAN_STATE_WHITESPACE) {
  8151. if (c == ';') {
  8152. state = UFBXI_ASCII_SCAN_STATE_COMMENT;
  8153. } else if (ufbxi_is_space(c)) {
  8154. src++;
  8155. } else {
  8156. state = UFBXI_ASCII_SCAN_STATE_VALUE;
  8157. }
  8158. } else if (state == UFBXI_ASCII_SCAN_STATE_COMMENT) {
  8159. if (c == '\n') {
  8160. state = UFBXI_ASCII_SCAN_STATE_WHITESPACE;
  8161. } else {
  8162. src++;
  8163. }
  8164. } else if (state == UFBXI_ASCII_SCAN_STATE_COMMA) {
  8165. state = UFBXI_ASCII_SCAN_STATE_WHITESPACE;
  8166. }
  8167. }
  8168. if (state == UFBXI_ASCII_SCAN_STATE_COMMA) {
  8169. // Parse a value from the buffer
  8170. if (buffer_value) {
  8171. const char *buffer_end = ufbxi_ascii_array_task_parse(t, buffer, buffer + buffer_len);
  8172. if (buffer_end == NULL || buffer_end == buffer) {
  8173. return false;
  8174. }
  8175. }
  8176. // If not at end, we are past the last comma, so try to find a
  8177. // safe range to parse.
  8178. if (src != end) {
  8179. const char *parse_end = end;
  8180. while (parse_end > src) {
  8181. if (parse_end[-1] == ',') break;
  8182. parse_end--;
  8183. }
  8184. if (src < parse_end) {
  8185. src = ufbxi_ascii_array_task_parse(t, src, parse_end);
  8186. if (src == NULL) return false;
  8187. }
  8188. }
  8189. buffer_len = 0;
  8190. buffer_value = false;
  8191. }
  8192. }
  8193. }
  8194. if (t->offset != t->arr_size) return false;
  8195. return true;
  8196. }
  8197. ufbxi_noinline static bool ufbxi_ascii_array_task_fn(ufbxi_task *task)
  8198. {
  8199. ufbxi_ascii_array_task *t = (ufbxi_ascii_array_task *)task->data;
  8200. if (!ufbxi_ascii_array_task_imp(t)) {
  8201. task->error = "Threaded ASCII parse error";
  8202. return false;
  8203. }
  8204. return true;
  8205. }
  8206. ufbxi_nodiscard static ufbxi_noinline int ufbxi_ascii_read_float_array(ufbxi_context *uc, char type, size_t *p_num_read)
  8207. {
  8208. ufbxi_ascii *ua = &uc->ascii;
  8209. if (ua->parse_as_f32) return 1;
  8210. double val;
  8211. if (ua->token.type == UFBXI_ASCII_FLOAT) {
  8212. val = ua->token.value.f64;
  8213. } else if (ua->token.type == UFBXI_ASCII_INT) {
  8214. double fsign = !ua->token.value.i64 && ua->token.negative ? -1.0 : 1.0;
  8215. val = (double)ua->token.value.i64 * fsign;
  8216. } else {
  8217. return 1;
  8218. }
  8219. const char *src = ua->src;
  8220. const char *end = ua->src_yield;
  8221. uint32_t parse_flags = uc->double_parse_flags | UFBXI_PARSE_DOUBLE_VERIFY_LENGTH;
  8222. size_t initial_items = uc->tmp_stack.num_items;
  8223. const char *src_scan = src;
  8224. for (;;) {
  8225. // Skip '\s*,\s*' between array elements. If we don't find a comma after an element
  8226. // don't push it as we can't be 100% certain whether it's a part of the array.
  8227. while (src_scan != end && ufbxi_is_space(*src_scan)) src_scan++;
  8228. if (src_scan == end || *src_scan != ',') break;
  8229. src_scan++;
  8230. while (src_scan != end && ufbxi_is_space(*src_scan)) src_scan++;
  8231. // Found comma, commit to the position and push the previous value to the array
  8232. src = src_scan;
  8233. if (type == 'd') {
  8234. double *v = ufbxi_push_fast(&uc->tmp_stack, double, 1);
  8235. ufbxi_check(v);
  8236. *v = (double)val;
  8237. } else if (type == 'f') {
  8238. float *v = ufbxi_push_fast(&uc->tmp_stack, float, 1);
  8239. ufbxi_check(v);
  8240. *v = (float)val;
  8241. }
  8242. // TODO: Collect ASCII numbers to deferred parse integer/string segments
  8243. // Try to parse the next value, we don't commit this until we find a comma after it above.
  8244. char *num_end = NULL;
  8245. size_t left = ufbxi_to_size(end - src_scan);
  8246. if (left < 64) break;
  8247. val = ufbxi_parse_double(src_scan, left - 2, &num_end, parse_flags);
  8248. if (!num_end || num_end == src_scan) {
  8249. break;
  8250. }
  8251. src_scan = num_end;
  8252. }
  8253. // Resume conventional parsing if we moved `src`.
  8254. if (src != ua->src) {
  8255. ua->src = src;
  8256. ufbxi_check(ufbxi_ascii_next_token(uc, &ua->token));
  8257. }
  8258. *p_num_read = uc->tmp_stack.num_items - initial_items;
  8259. return 1;
  8260. }
  8261. // Recursion limited by check at the start
  8262. ufbxi_nodiscard ufbxi_noinline static int ufbxi_ascii_parse_node(ufbxi_context *uc, uint32_t depth, ufbxi_parse_state parent_state, bool *p_end, ufbxi_buf *tmp_buf, bool recursive)
  8263. ufbxi_recursive_function(int, ufbxi_ascii_parse_node, (uc, depth, parent_state, p_end, tmp_buf, recursive), UFBXI_MAX_NODE_DEPTH + 1,
  8264. (ufbxi_context *uc, uint32_t depth, ufbxi_parse_state parent_state, bool *p_end, ufbxi_buf *tmp_buf, bool recursive))
  8265. {
  8266. ufbxi_ascii *ua = &uc->ascii;
  8267. if (ua->token.type == '}') {
  8268. ufbxi_check(ufbxi_ascii_next_token(uc, &ua->token));
  8269. *p_end = true;
  8270. return 1;
  8271. }
  8272. if (ua->token.type == UFBXI_ASCII_END) {
  8273. ufbxi_check_msg(depth == 0, "Truncated file");
  8274. *p_end = true;
  8275. return 1;
  8276. }
  8277. // Parse the name eg. "Node:" token and intern the name
  8278. ufbxi_check(depth < UFBXI_MAX_NODE_DEPTH);
  8279. if (!uc->sure_fbx && depth == 0 && ua->token.type != UFBXI_ASCII_NAME) {
  8280. ufbxi_fail_msg("Expected a 'Name:' token", "Not an FBX file");
  8281. }
  8282. ufbxi_check(ufbxi_ascii_accept(uc, UFBXI_ASCII_NAME));
  8283. size_t name_len = ua->prev_token.value.name_len;
  8284. ufbxi_check(name_len <= 0xff);
  8285. const char *name = ufbxi_push_string(&uc->string_pool, ua->prev_token.str_data, ua->prev_token.str_len, NULL, true);
  8286. ufbxi_check(name);
  8287. // Push the parsed node into the `tmp_stack` buffer, the nodes will be popped by
  8288. // calling code after its done parsing all of it's children.
  8289. ufbxi_node *node = ufbxi_push_zero(&uc->tmp_stack, ufbxi_node, 1);
  8290. ufbxi_check(node);
  8291. node->name = name;
  8292. node->name_len = (uint8_t)name_len;
  8293. bool in_ascii_array = false;
  8294. uint32_t num_values = 0;
  8295. uint32_t type_mask = 0;
  8296. int arr_type = 0;
  8297. ufbxi_buf *arr_buf = NULL;
  8298. size_t arr_elem_size = 0;
  8299. // Check if the values of the node we're parsing currently should be
  8300. // treated as an array.
  8301. ufbxi_array_info arr_info;
  8302. if (ufbxi_is_array_node(uc, parent_state, name, &arr_info)) {
  8303. uint32_t flags = arr_info.flags;
  8304. arr_type = ufbxi_normalize_array_type(arr_info.type, 'b');
  8305. arr_buf = tmp_buf;
  8306. if (flags & UFBXI_ARRAY_FLAG_RESULT) arr_buf = &uc->result;
  8307. else if (flags & UFBXI_ARRAY_FLAG_TMP_BUF) arr_buf = &uc->tmp;
  8308. ufbxi_value_array *arr = ufbxi_push(tmp_buf, ufbxi_value_array, 1);
  8309. ufbxi_check(arr);
  8310. node->value_type_mask = UFBXI_VALUE_ARRAY;
  8311. node->array = arr;
  8312. arr->type = (char)arr_type;
  8313. // Parse array values using strtof() if the array destination is 32-bit float
  8314. // since KeyAttrDataFloat packs integer data (!) into floating point values so we
  8315. // should try to be as exact as possible.
  8316. if (arr_info.flags & UFBXI_ARRAY_FLAG_ACCURATE_F32) {
  8317. ua->parse_as_f32 = true;
  8318. }
  8319. arr_elem_size = ufbxi_array_type_size((char)arr_type);
  8320. if (arr_type != '-') {
  8321. // Force alignment for array contents: This allows us to use `ufbxi_push_fast()`
  8322. // in fast parsing functions.
  8323. ufbxi_check(ufbxi_push_size_zero(&uc->tmp_stack, 8, 1));
  8324. // Pad with 4 zero elements to make indexing with `-1` safe.
  8325. if ((flags & UFBXI_ARRAY_FLAG_PAD_BEGIN) != 0) {
  8326. ufbxi_check(ufbxi_push_size_zero(&uc->tmp_stack, arr_elem_size, 4));
  8327. num_values += 4;
  8328. }
  8329. }
  8330. }
  8331. // Some fields in ASCII may have leading commas eg. `Content: , "base64-string"`
  8332. if (ua->token.type == ',') {
  8333. // HACK: If we are parsing an "array" that should be ignored, ie. `Content` when
  8334. // `opts.ignore_embedded == true` try to skip the next token string if possible.
  8335. if (arr_type == '-') {
  8336. if (!ufbxi_ascii_try_ignore_string(uc, &ua->token)) {
  8337. ufbxi_check(ufbxi_ascii_next_token(uc, &ua->token));
  8338. }
  8339. } else {
  8340. ufbxi_check(ufbxi_ascii_next_token(uc, &ua->token));
  8341. }
  8342. }
  8343. ufbxi_parse_state parse_state = ufbxi_update_parse_state(parent_state, node->name);
  8344. ufbxi_value vals[UFBXI_MAX_NON_ARRAY_VALUES];
  8345. uint32_t deferred_size = 0;
  8346. // NOTE: Infinite loop to allow skipping the comma parsing via `continue`.
  8347. for (;;) {
  8348. ufbxi_ascii_token *tok = &ua->prev_token;
  8349. if (arr_type) {
  8350. size_t num_read = 0;
  8351. if (arr_type == 'f' || arr_type == 'd') {
  8352. ufbxi_check(ufbxi_ascii_read_float_array(uc, (char)arr_type, &num_read));
  8353. } else if (arr_type == 'i' || arr_type == 'l') {
  8354. ufbxi_check(ufbxi_ascii_read_int_array(uc, (char)arr_type, &num_read));
  8355. }
  8356. ufbxi_check(UINT32_MAX - num_values > num_read);
  8357. num_values += (uint32_t)num_read;
  8358. }
  8359. if (ufbxi_ascii_accept(uc, UFBXI_ASCII_STRING)) {
  8360. if (arr_type) {
  8361. if (arr_type == 's' || arr_type == 'S' || arr_type == 'C') {
  8362. bool raw = arr_type == 's';
  8363. ufbx_string *v = ufbxi_push(&uc->tmp_stack, ufbx_string, 1);
  8364. ufbxi_check(v);
  8365. v->data = tok->str_data;
  8366. v->length = tok->str_len;
  8367. if (arr_type == 'C') {
  8368. ufbxi_buf *buf = uc->opts.retain_dom ? &uc->result : tmp_buf;
  8369. v->data = ufbxi_push_copy(buf, char, v->length, v->data);
  8370. ufbxi_check(v->data);
  8371. } else {
  8372. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, v, raw));
  8373. }
  8374. } else {
  8375. // Ignore strings in non-string arrays, decrement `num_values` as it will be
  8376. // incremented after the loop iteration is done to ignore it.
  8377. num_values--;
  8378. }
  8379. } else if (num_values < UFBXI_MAX_NON_ARRAY_VALUES) {
  8380. type_mask |= (uint32_t)UFBXI_VALUE_STRING << (num_values*2);
  8381. ufbxi_value *v = &vals[num_values];
  8382. const char *str = tok->str_data;
  8383. size_t length = tok->str_len;
  8384. ufbxi_check(str);
  8385. if (length == 0) {
  8386. v->s.raw_data = ufbxi_empty_char;
  8387. v->s.raw_length = 0;
  8388. v->s.utf8_length = 0;
  8389. } else {
  8390. bool non_ascii = false;
  8391. uint32_t hash = ufbxi_hash_string_check_ascii(str, length, &non_ascii);
  8392. bool raw = !non_ascii || ufbxi_is_raw_string(uc, parent_state, name, num_values);
  8393. ufbxi_check(ufbxi_push_sanitized_string(&uc->string_pool, &v->s, str, length, hash, raw));
  8394. if (non_ascii && raw) v->s.utf8_length = UINT32_MAX;
  8395. }
  8396. }
  8397. } else if (ufbxi_ascii_accept(uc, UFBXI_ASCII_INT)) {
  8398. int64_t val = tok->value.i64;
  8399. ufbx_real fsign = !val && tok->negative ? (ufbx_real)-1.0f : (ufbx_real)1.0f;
  8400. switch (arr_type) {
  8401. case 0:
  8402. // Parse version from comment if there was no magic comment
  8403. if (!ua->found_version && parse_state == UFBXI_PARSE_FBX_VERSION && num_values == 0) {
  8404. if (val >= 6000 && val <= 10000) {
  8405. ua->found_version = true;
  8406. uc->version = (uint32_t)val;
  8407. }
  8408. }
  8409. if (num_values < UFBXI_MAX_NON_ARRAY_VALUES) {
  8410. type_mask |= (uint32_t)UFBXI_VALUE_NUMBER << (num_values*2);
  8411. ufbxi_value *v = &vals[num_values];
  8412. // False positive: `v->f` and `v->i` do not overlap in the union.
  8413. // cppcheck-suppress overlappingWriteUnion
  8414. v->f = (double)(v->i = val) * (double)fsign;
  8415. }
  8416. break;
  8417. case 'b': { bool *v = ufbxi_push(&uc->tmp_stack, bool, 1); ufbxi_check(v); *v = val != 0; } break;
  8418. case 'c': { uint8_t *v = ufbxi_push(&uc->tmp_stack, uint8_t, 1); ufbxi_check(v); *v = (uint8_t)val; } break;
  8419. case 'i': { int32_t *v = ufbxi_push(&uc->tmp_stack, int32_t, 1); ufbxi_check(v); *v = (int32_t)val; } break;
  8420. case 'l': { int64_t *v = ufbxi_push(&uc->tmp_stack, int64_t, 1); ufbxi_check(v); *v = (int64_t)val; } break;
  8421. case 'f': { float *v = ufbxi_push(&uc->tmp_stack, float, 1); ufbxi_check(v); *v = (float)val * (float)fsign; } break;
  8422. case 'd': { double *v = ufbxi_push(&uc->tmp_stack, double, 1); ufbxi_check(v); *v = (double)val * (double)fsign; } break;
  8423. case '-': num_values--; break;
  8424. default:
  8425. ufbxi_fail("Bad array dst type");
  8426. }
  8427. } else if (ufbxi_ascii_accept(uc, UFBXI_ASCII_FLOAT)) {
  8428. double val = tok->value.f64;
  8429. switch (arr_type) {
  8430. case 0:
  8431. if (num_values < UFBXI_MAX_NON_ARRAY_VALUES) {
  8432. type_mask |= (uint32_t)UFBXI_VALUE_NUMBER << (num_values*2);
  8433. ufbxi_value *v = &vals[num_values];
  8434. // False positive: `v->f` and `v->i` do not overlap in the union.
  8435. // cppcheck-suppress overlappingWriteUnion
  8436. v->i = ufbxi_f64_to_i64(v->f = val);
  8437. }
  8438. break;
  8439. case 'b': { bool *v = ufbxi_push(&uc->tmp_stack, bool, 1); ufbxi_check(v); *v = val != 0; } break;
  8440. case 'c': { uint8_t *v = ufbxi_push(&uc->tmp_stack, uint8_t, 1); ufbxi_check(v); *v = (uint8_t)val; } break;
  8441. case 'i': { int32_t *v = ufbxi_push(&uc->tmp_stack, int32_t, 1); ufbxi_check(v); *v = ufbxi_f64_to_i32(val); } break;
  8442. case 'l': { int64_t *v = ufbxi_push(&uc->tmp_stack, int64_t, 1); ufbxi_check(v); *v = ufbxi_f64_to_i64(val); } break;
  8443. case 'f': { float *v = ufbxi_push(&uc->tmp_stack, float, 1); ufbxi_check(v); *v = (float)val; } break;
  8444. case 'd': { double *v = ufbxi_push(&uc->tmp_stack, double, 1); ufbxi_check(v); *v = (double)val; } break;
  8445. case '-': num_values--; break;
  8446. default:
  8447. ufbxi_fail("Bad array dst type");
  8448. }
  8449. } else if (ufbxi_ascii_accept(uc, UFBXI_ASCII_BARE_WORD)) {
  8450. int64_t val = 0;
  8451. if (tok->str_len >= 1) {
  8452. val = (int64_t)tok->str_data[0];
  8453. }
  8454. switch (arr_type) {
  8455. case 0:
  8456. if (num_values < UFBXI_MAX_NON_ARRAY_VALUES) {
  8457. type_mask |= (uint32_t)UFBXI_VALUE_NUMBER << (num_values*2);
  8458. ufbxi_value *v = &vals[num_values];
  8459. // False positive: `v->f` and `v->i` do not overlap in the union.
  8460. // cppcheck-suppress overlappingWriteUnion
  8461. v->f = (double)(v->i = val);
  8462. }
  8463. break;
  8464. case 'b': { bool *v = ufbxi_push(&uc->tmp_stack, bool, 1); ufbxi_check(v); *v = val != 0; } break;
  8465. case 'c': { uint8_t *v = ufbxi_push(&uc->tmp_stack, uint8_t, 1); ufbxi_check(v); *v = (uint8_t)val; } break;
  8466. case 'i': { int32_t *v = ufbxi_push(&uc->tmp_stack, int32_t, 1); ufbxi_check(v); *v = (int32_t)val; } break;
  8467. case 'l': { int64_t *v = ufbxi_push(&uc->tmp_stack, int64_t, 1); ufbxi_check(v); *v = (int64_t)val; } break;
  8468. case 'f': { float *v = ufbxi_push(&uc->tmp_stack, float, 1); ufbxi_check(v); *v = (float)val; } break;
  8469. case 'd': { double *v = ufbxi_push(&uc->tmp_stack, double, 1); ufbxi_check(v); *v = (double)val; } break;
  8470. case '-': num_values--; break;
  8471. default:
  8472. ufbxi_fail("Bad array dst type");
  8473. }
  8474. } else if (ufbxi_ascii_accept(uc, '*')) {
  8475. // Parse a post-7000 ASCII array eg. "*3 { 1,2,3 }"
  8476. ufbxi_check(!in_ascii_array);
  8477. ufbxi_check(ufbxi_ascii_accept(uc, UFBXI_ASCII_INT));
  8478. int64_t count = ua->prev_token.value.i64;
  8479. if (ufbxi_ascii_accept(uc, '{')) {
  8480. ufbxi_check(ufbxi_ascii_accept(uc, UFBXI_ASCII_NAME));
  8481. in_ascii_array = true;
  8482. // Optimized array skipping and threaded parsing
  8483. if (arr_type == '-') {
  8484. ufbxi_check(ufbxi_ascii_skip_until(uc, '}'));
  8485. } else if (uc->parse_threaded && !uc->opts.force_single_thread_ascii_parsing
  8486. && !ua->parse_as_f32
  8487. && (arr_type == 'i' || arr_type == 'l' || arr_type == 'f' || arr_type == 'd')) {
  8488. // Don't bother with small arrays due to fixed overhead
  8489. if (count >= UFBXI_MIN_THREADED_ASCII_VALUES && count <= UINT32_MAX) {
  8490. deferred_size = (uint32_t)count - 1;
  8491. ufbxi_check(ufbxi_ascii_store_array(uc, tmp_buf));
  8492. }
  8493. }
  8494. }
  8495. // NOTE: This `continue` skips incrementing `num_values` and parsing
  8496. // a comma, continuing to parse the values in the array.
  8497. continue;
  8498. } else {
  8499. break;
  8500. }
  8501. // Add value and keep parsing if there's a comma. This part may be
  8502. // skipped if we enter an array block.
  8503. num_values++;
  8504. ufbxi_check(num_values < UINT32_MAX);
  8505. if (!ufbxi_ascii_accept(uc, ',')) break;
  8506. }
  8507. // Close the ASCII array if we are in one
  8508. if (in_ascii_array) {
  8509. ufbxi_check(ufbxi_ascii_accept(uc, '}'));
  8510. }
  8511. ua->parse_as_f32 = false;
  8512. if (arr_type) {
  8513. if (arr_type == '-') {
  8514. node->array->data = NULL;
  8515. node->array->size = 0;
  8516. } else {
  8517. void *arr_data = NULL;
  8518. if (deferred_size > 0) {
  8519. arr_data = ufbxi_push_size(arr_buf, arr_elem_size, num_values + deferred_size);
  8520. // Pop any previously pushed values
  8521. if (num_values > 0) {
  8522. ufbxi_pop_size(&uc->tmp_stack, arr_elem_size, num_values, arr_data, false);
  8523. }
  8524. } else {
  8525. arr_data = ufbxi_push_pop_size(arr_buf, &uc->tmp_stack, arr_elem_size, num_values);
  8526. }
  8527. ufbxi_check(arr_data);
  8528. if (arr_info.flags & UFBXI_ARRAY_FLAG_PAD_BEGIN) {
  8529. node->array->data = (char*)arr_data + 4*arr_elem_size;
  8530. node->array->size = num_values + deferred_size - 4;
  8531. } else {
  8532. node->array->data = arr_data;
  8533. node->array->size = num_values + deferred_size;
  8534. }
  8535. // Pop alignment helper
  8536. ufbxi_pop_size(&uc->tmp_stack, 8, 1, NULL, false);
  8537. // Deferred parsing
  8538. if (deferred_size > 0) {
  8539. size_t num_spans = uc->tmp_ascii_spans.num_items;
  8540. ufbxi_ascii_span *spans = ufbxi_push_pop(tmp_buf, &uc->tmp_ascii_spans, ufbxi_ascii_span, num_spans);
  8541. ufbxi_check(spans);
  8542. ufbxi_ascii_array_task t; // ufbxi_uninit
  8543. t.arr_data = (char*)arr_data + num_values * arr_elem_size;
  8544. t.arr_type = (char)arr_type;
  8545. t.arr_size = deferred_size;
  8546. t.num_spans = num_spans;
  8547. t.spans = spans;
  8548. t.offset = 0;
  8549. // TODO: Split these further
  8550. ufbxi_task *task = ufbxi_thread_pool_create_task(&uc->thread_pool, &ufbxi_ascii_array_task_fn);
  8551. if (task) {
  8552. task->data = ufbxi_push_copy(tmp_buf, ufbxi_ascii_array_task, 1, &t);
  8553. ufbxi_check(task->data);
  8554. ufbxi_thread_pool_run_task(&uc->thread_pool, task);
  8555. } else {
  8556. ufbxi_check_msg(ufbxi_ascii_array_task_imp(&t), "Threaded ASCII parse error");
  8557. }
  8558. }
  8559. }
  8560. } else {
  8561. num_values = ufbxi_min32(num_values, UFBXI_MAX_NON_ARRAY_VALUES);
  8562. node->value_type_mask = (uint16_t)type_mask;
  8563. node->vals = ufbxi_push_copy(tmp_buf, ufbxi_value, num_values, vals);
  8564. ufbxi_check(node->vals);
  8565. }
  8566. // Recursively parse the children of this node. Update the parse state
  8567. // to provide context for child node parsing.
  8568. if (ufbxi_ascii_accept(uc, '{')) {
  8569. if (recursive) {
  8570. size_t num_children = 0;
  8571. for (;;) {
  8572. bool end = false;
  8573. ufbxi_check(ufbxi_ascii_parse_node(uc, depth + 1, parse_state, &end, tmp_buf, recursive));
  8574. if (end) break;
  8575. num_children++;
  8576. }
  8577. // Pop children from `tmp_stack` to a contiguous array
  8578. node->children = ufbxi_push_pop(tmp_buf, &uc->tmp_stack, ufbxi_node, num_children);
  8579. ufbxi_check(node->children);
  8580. node->num_children = (uint32_t)num_children;
  8581. }
  8582. uc->has_next_child = true;
  8583. } else {
  8584. uc->has_next_child = false;
  8585. }
  8586. return 1;
  8587. }
  8588. // -- DOM retention
  8589. typedef struct {
  8590. uintptr_t node_ptr;
  8591. ufbx_dom_node *dom_node;
  8592. } ufbxi_dom_mapping;
  8593. ufbxi_nodiscard static ufbxi_noinline ufbx_dom_node *ufbxi_get_dom_node_imp(ufbxi_context *uc, ufbxi_node *node)
  8594. {
  8595. if (!node) return NULL;
  8596. ufbxi_dom_mapping mapping = { (uintptr_t)node, NULL };
  8597. uint32_t hash = ufbxi_hash_uptr(mapping.node_ptr);
  8598. ufbxi_dom_mapping *result = ufbxi_map_find(&uc->dom_node_map, ufbxi_dom_mapping, hash, &mapping);
  8599. return result ? result->dom_node : NULL;
  8600. }
  8601. ufbxi_nodiscard static ufbxi_forceinline ufbx_dom_node *ufbxi_get_dom_node(ufbxi_context *uc, ufbxi_node *node)
  8602. {
  8603. if (!uc->opts.retain_dom) return NULL;
  8604. return ufbxi_get_dom_node_imp(uc, node);
  8605. }
  8606. // Recursion limited by check in ufbxi_[binary/ascii]_parse_node()
  8607. ufbxi_nodiscard static ufbxi_noinline int ufbxi_retain_dom_node(ufbxi_context *uc, ufbxi_node *node, ufbx_dom_node **p_dom_node)
  8608. ufbxi_recursive_function(int, ufbxi_retain_dom_node, (uc, node, p_dom_node), UFBXI_MAX_NODE_DEPTH + 1,
  8609. (ufbxi_context *uc, ufbxi_node *node, ufbx_dom_node **p_dom_node))
  8610. {
  8611. ufbx_dom_node *dst = ufbxi_push_zero(&uc->result, ufbx_dom_node, 1);
  8612. ufbxi_check(dst);
  8613. ufbxi_check(ufbxi_push_copy(&uc->tmp_dom_nodes, ufbx_dom_node*, 1, &dst));
  8614. if (p_dom_node) {
  8615. *p_dom_node = dst;
  8616. }
  8617. dst->name.data = node->name;
  8618. dst->name.length = node->name_len;
  8619. {
  8620. ufbxi_dom_mapping mapping = { (uintptr_t)node, NULL };
  8621. uint32_t hash = ufbxi_hash_uptr(mapping.node_ptr);
  8622. ufbxi_dom_mapping *result = ufbxi_map_find(&uc->dom_node_map, ufbxi_dom_mapping, hash, &mapping);
  8623. if (!result) {
  8624. result = ufbxi_map_insert(&uc->dom_node_map, ufbxi_dom_mapping, hash, &mapping);
  8625. ufbxi_check(result);
  8626. }
  8627. result->node_ptr = (uintptr_t)node;
  8628. result->dom_node = dst;
  8629. }
  8630. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &dst->name, false));
  8631. if (node->value_type_mask == UFBXI_VALUE_ARRAY) {
  8632. ufbxi_value_array *arr = node->array;
  8633. ufbx_dom_value *val = ufbxi_push_zero(&uc->result, ufbx_dom_value, 1);
  8634. ufbxi_check(val);
  8635. dst->values.data = val;
  8636. dst->values.count = 1;
  8637. size_t elem_size = ufbxi_array_type_size(arr->type);
  8638. val->value_str.data = ufbxi_empty_char;
  8639. val->value_blob.data = arr->data;
  8640. val->value_blob.size = arr->size * elem_size;
  8641. val->value_float = (double)(val->value_int = (int64_t)arr->size);
  8642. switch (arr->type) {
  8643. case 'c': val->type = UFBX_DOM_VALUE_ARRAY_I8; break;
  8644. case 'b': val->type = UFBX_DOM_VALUE_ARRAY_I8; break;
  8645. case 'i': val->type = UFBX_DOM_VALUE_ARRAY_I32; break;
  8646. case 'l': val->type = UFBX_DOM_VALUE_ARRAY_I64; break;
  8647. case 'f': val->type = UFBX_DOM_VALUE_ARRAY_F32; break;
  8648. case 'd': val->type = UFBX_DOM_VALUE_ARRAY_F64; break;
  8649. case 's': val->type = UFBX_DOM_VALUE_ARRAY_RAW_STRING; break;
  8650. case 'C': val->type = UFBX_DOM_VALUE_ARRAY_RAW_STRING; break;
  8651. case '-': val->type = UFBX_DOM_VALUE_ARRAY_IGNORED; break;
  8652. default: ufbxi_fail("Bad array type");
  8653. }
  8654. } else {
  8655. size_t ix;
  8656. for (ix = 0; ix < UFBXI_MAX_NON_ARRAY_VALUES; ix++) {
  8657. uint32_t mask = (node->value_type_mask >> (2*ix)) & 0x3;
  8658. if (!mask) break;
  8659. ufbx_dom_value *val = ufbxi_push_zero(&uc->tmp_stack, ufbx_dom_value, 1);
  8660. ufbxi_check(val);
  8661. val->value_str.data = ufbxi_empty_char;
  8662. if (mask == UFBXI_VALUE_STRING) {
  8663. val->type = UFBX_DOM_VALUE_STRING;
  8664. ufbxi_ignore(ufbxi_get_val_at(node, ix, 'S', &val->value_str));
  8665. ufbxi_ignore(ufbxi_get_val_at(node, ix, 'b', &val->value_blob));
  8666. } else {
  8667. ufbx_assert(mask == UFBXI_VALUE_NUMBER);
  8668. val->type = UFBX_DOM_VALUE_NUMBER;
  8669. val->value_int = node->vals[ix].i;
  8670. val->value_float = node->vals[ix].f;
  8671. }
  8672. }
  8673. dst->values.count = ix;
  8674. dst->values.data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_dom_value, ix);
  8675. ufbxi_check(dst->values.data);
  8676. }
  8677. if (node->num_children > 0) {
  8678. ufbxi_for(ufbxi_node, child, node->children, node->num_children) {
  8679. ufbxi_check(ufbxi_retain_dom_node(uc, child, NULL));
  8680. }
  8681. dst->children.count = node->num_children;
  8682. dst->children.data = ufbxi_push_pop(&uc->result, &uc->tmp_dom_nodes, ufbx_dom_node*, node->num_children);
  8683. ufbxi_check(dst->children.data);
  8684. }
  8685. return 1;
  8686. }
  8687. ufbxi_nodiscard static ufbxi_noinline int ufbxi_retain_toplevel(ufbxi_context *uc, ufbxi_node *node)
  8688. {
  8689. if (uc->dom_parse_num_children > 0) {
  8690. ufbx_dom_node **children = ufbxi_push_pop(&uc->result, &uc->tmp_dom_nodes, ufbx_dom_node*, uc->dom_parse_num_children);
  8691. ufbxi_check(children);
  8692. uc->dom_parse_toplevel->children.data = children;
  8693. uc->dom_parse_toplevel->children.count = uc->dom_parse_num_children;
  8694. uc->dom_parse_num_children = 0;
  8695. }
  8696. if (node) {
  8697. ufbxi_check(ufbxi_retain_dom_node(uc, node, &uc->dom_parse_toplevel));
  8698. } else {
  8699. uc->dom_parse_toplevel = NULL;
  8700. // Called with NULL argument to finish retaining DOM, collect the final nodes to `ufbx_scene`.
  8701. size_t num_top_nodes = uc->tmp_dom_nodes.num_items;
  8702. ufbx_dom_node **nodes = ufbxi_push_pop(&uc->result, &uc->tmp_dom_nodes, ufbx_dom_node*, num_top_nodes);
  8703. ufbxi_check(nodes);
  8704. ufbx_dom_node *dom_root = ufbxi_push_zero(&uc->result, ufbx_dom_node, 1);
  8705. ufbxi_check(dom_root);
  8706. dom_root->name.data = ufbxi_empty_char;
  8707. dom_root->children.data = nodes;
  8708. dom_root->children.count = num_top_nodes;
  8709. uc->scene.dom_root = dom_root;
  8710. }
  8711. return 1;
  8712. }
  8713. ufbxi_nodiscard static ufbxi_noinline int ufbxi_retain_toplevel_child(ufbxi_context *uc, ufbxi_node *child)
  8714. {
  8715. ufbx_assert(uc->dom_parse_toplevel);
  8716. ufbxi_check(ufbxi_retain_dom_node(uc, child, NULL));
  8717. uc->dom_parse_num_children++;
  8718. return 1;
  8719. }
  8720. // -- General parsing
  8721. static ufbxi_noinline bool ufbxi_next_line(ufbx_string *line, ufbx_string *buf, bool skip_space)
  8722. {
  8723. if (buf->length == 0) return false;
  8724. const char *newline = (const char*)memchr(buf->data, '\n', buf->length);
  8725. size_t length = newline ? ufbxi_to_size(newline - buf->data) + 1 : buf->length;
  8726. line->data = buf->data;
  8727. line->length = length;
  8728. buf->data += length;
  8729. buf->length -= length;
  8730. if (skip_space) {
  8731. while (line->length > 0 && ufbxi_is_space(line->data[0])) {
  8732. line->data++;
  8733. line->length--;
  8734. }
  8735. while (line->length > 0 && ufbxi_is_space(line->data[line->length - 1])) {
  8736. line->length--;
  8737. }
  8738. }
  8739. return true;
  8740. }
  8741. // Recursion limited by compile time patterns
  8742. static ufbxi_noinline const char *ufbxi_match_skip(const char *fmt, bool alternation)
  8743. ufbxi_recursive_function(const char *, ufbxi_match_skip, (fmt, alternation), 4,
  8744. (const char *fmt, bool alternation))
  8745. {
  8746. for (;;) {
  8747. char c = *fmt++;
  8748. switch (c) {
  8749. case '(':
  8750. fmt = ufbxi_match_skip(fmt, false) + 1;
  8751. break;
  8752. case '\\':
  8753. fmt++;
  8754. break;
  8755. case '[':
  8756. c = *fmt;
  8757. while (c != ']') {
  8758. c = *fmt++;
  8759. if (c == '\\') {
  8760. c = *fmt++;
  8761. }
  8762. }
  8763. fmt++;
  8764. break;
  8765. case '|':
  8766. if (alternation) return fmt - 1;
  8767. break;
  8768. case ')':
  8769. case '\0':
  8770. return fmt - 1;
  8771. default: break;
  8772. }
  8773. }
  8774. }
  8775. // Recursion limited by compile time patterns
  8776. static ufbxi_noinline bool ufbxi_match_imp(const char **p_str, const char *end, const char **p_fmt)
  8777. ufbxi_recursive_function(bool, ufbxi_match_imp, (p_str, end, p_fmt), 4,
  8778. (const char **p_str, const char *end, const char **p_fmt))
  8779. {
  8780. const char *str_original_begin = *p_str;
  8781. const char *str = str_original_begin;
  8782. const char *fmt_begin = *p_fmt;
  8783. const char *fmt = fmt_begin;
  8784. bool case_insensitive = false;
  8785. size_t count = 0;
  8786. for (;;) {
  8787. char c = *fmt++;
  8788. if (!c) {
  8789. *p_str = str;
  8790. *p_fmt = fmt - 1;
  8791. return true;
  8792. }
  8793. const char *str_begin = str;
  8794. char ref = str != end ? *str : '\0';
  8795. if (case_insensitive) {
  8796. if (ref >= 'A' && ref <= 'Z') {
  8797. ref = (char)((int)(ref - 'A') + 'a');
  8798. }
  8799. }
  8800. bool ok = false;
  8801. switch (c) {
  8802. case '\\': {
  8803. const char *macro = NULL;
  8804. c = *fmt++;
  8805. switch (c) {
  8806. case 'd':
  8807. macro = "[0-9]";
  8808. break;
  8809. case 'F':
  8810. macro = "[\\-+]?[0-9]+(\\.[0-9]+)?([eE][\\-+]?[0-9]+)?";
  8811. break;
  8812. case 's':
  8813. if (ufbxi_is_space(ref)) {
  8814. ok = true;
  8815. str++;
  8816. }
  8817. break;
  8818. case 'S':
  8819. if (!ufbxi_is_space(ref)) {
  8820. ok = true;
  8821. str++;
  8822. }
  8823. break;
  8824. case 'c':
  8825. case 'C':
  8826. case_insensitive = c == 'c';
  8827. ok = true;
  8828. break;
  8829. default:
  8830. if (ref == c) {
  8831. ok = true;
  8832. str++;
  8833. }
  8834. break;
  8835. }
  8836. if (macro) {
  8837. ok = ufbxi_match_imp(&str, end, &macro);
  8838. }
  8839. } break;
  8840. case '[': {
  8841. while (fmt[0] != ']') {
  8842. if (fmt[0] == '\\') {
  8843. if (ref == fmt[1]) ok = true;
  8844. fmt += 2;
  8845. } else if (fmt[1] == '-') {
  8846. if (ref >= fmt[0] && ref <= fmt[2]) {
  8847. ok = true;
  8848. }
  8849. fmt += 3;
  8850. } else {
  8851. if (ref == fmt[0]) ok = true;
  8852. fmt += 1;
  8853. }
  8854. }
  8855. fmt++;
  8856. if (ok) str++;
  8857. } break;
  8858. case '(':
  8859. if (ufbxi_match_imp(&str, end, &fmt)) {
  8860. ok = true;
  8861. }
  8862. break;
  8863. case '|':
  8864. fmt = ufbxi_match_skip(fmt, false);
  8865. ok = true;
  8866. break;
  8867. case ')':
  8868. *p_str = str;
  8869. *p_fmt = fmt;
  8870. return true;
  8871. case '.':
  8872. if (ref != '\0') {
  8873. ok = true;
  8874. str++;
  8875. }
  8876. break;
  8877. default:
  8878. if (c == ref) {
  8879. str++;
  8880. ok = true;
  8881. }
  8882. break;
  8883. }
  8884. bool did_fail = false;
  8885. c = *fmt;
  8886. switch (c) {
  8887. case '*':
  8888. fmt++;
  8889. if (ok) {
  8890. fmt = fmt_begin;
  8891. count++;
  8892. continue;
  8893. }
  8894. break;
  8895. case '+':
  8896. fmt++;
  8897. if (ok) {
  8898. fmt = fmt_begin;
  8899. count++;
  8900. continue;
  8901. } else if (count == 0) {
  8902. did_fail = true;
  8903. }
  8904. break;
  8905. case '?':
  8906. fmt++;
  8907. break;
  8908. default:
  8909. did_fail = !ok;
  8910. break;
  8911. }
  8912. if (did_fail) {
  8913. fmt = ufbxi_match_skip(fmt, true);
  8914. if (*fmt == '|') {
  8915. fmt++;
  8916. str = str_original_begin;
  8917. } else {
  8918. *p_fmt = ufbxi_match_skip(fmt, false) + 1;
  8919. return false;
  8920. }
  8921. } else {
  8922. if (!ok) {
  8923. str = str_begin;
  8924. }
  8925. }
  8926. fmt_begin = fmt;
  8927. count = 0;
  8928. }
  8929. }
  8930. static ufbxi_noinline bool ufbxi_match(const ufbx_string *str, const char *fmt)
  8931. {
  8932. const char *ptr = str->data, *end = str->data + str->length;
  8933. if (ufbxi_match_imp(&ptr, end, &fmt)) {
  8934. return ptr == end;
  8935. } else {
  8936. return false;
  8937. }
  8938. }
  8939. static ufbxi_noinline bool ufbxi_is_format(const char *data, size_t size, ufbx_file_format format)
  8940. {
  8941. ufbx_string line, buf = { data, size };
  8942. if (format == UFBX_FILE_FORMAT_FBX) {
  8943. if (size >= UFBXI_BINARY_MAGIC_SIZE && !memcmp(data, ufbxi_binary_magic, UFBXI_BINARY_MAGIC_SIZE)) {
  8944. return true;
  8945. }
  8946. while (ufbxi_next_line(&line, &buf, true)) {
  8947. if (ufbxi_match(&line, ";\\s*FBX\\s*\\d+\\.\\d+\\.\\d+\\s*project\\s+file")) return true;
  8948. if (ufbxi_match(&line, "FBXHeaderExtension:.*")) return true;
  8949. }
  8950. } else if (format == UFBX_FILE_FORMAT_OBJ) {
  8951. while (ufbxi_next_line(&line, &buf, true)) {
  8952. const char *pattern =
  8953. "(vn?\\s+\\F|vt)\\s+\\F\\s+\\F.*" "|"
  8954. "f\\s+[\\-/0-9]+\\s+[\\-/0-9]+\\s*[\\-/0-9]+.*" "|"
  8955. "(usemtl|mtllib)\\s+\\S.*";
  8956. if (ufbxi_match(&line, pattern)) return true;
  8957. }
  8958. } else if (format == UFBX_FILE_FORMAT_MTL) {
  8959. while (ufbxi_next_line(&line, &buf, true)) {
  8960. const char *pattern =
  8961. "newmtl\\s+\\S.*";
  8962. if (ufbxi_match(&line, pattern)) return true;
  8963. }
  8964. } else {
  8965. ufbxi_unreachable("Unhandled format");
  8966. }
  8967. return false;
  8968. }
  8969. ufbxi_nodiscard static ufbxi_noinline int ufbxi_determine_format(ufbxi_context *uc)
  8970. {
  8971. ufbx_file_format format = uc->opts.file_format;
  8972. if (format == UFBX_FILE_FORMAT_UNKNOWN && !uc->opts.no_format_from_content) {
  8973. ufbxi_pause_progress(uc);
  8974. size_t lookahead = UFBXI_MIN_FILE_FORMAT_LOOKAHEAD;
  8975. while (format == UFBX_FILE_FORMAT_UNKNOWN && lookahead <= uc->opts.file_format_lookahead) {
  8976. if (lookahead > uc->data_size) {
  8977. if (uc->eof) break;
  8978. ufbxi_check(ufbxi_refill(uc, lookahead, false));
  8979. }
  8980. size_t data_size = ufbxi_min_sz(lookahead, uc->data_size);
  8981. ufbxi_check_msg(data_size > 0, "Empty file");
  8982. for (uint32_t fmt = UFBX_FILE_FORMAT_FBX; fmt < UFBX_FILE_FORMAT_COUNT; fmt++) {
  8983. if (ufbxi_is_format(uc->data, data_size, (ufbx_file_format)fmt)) {
  8984. format = (ufbx_file_format)fmt;
  8985. break;
  8986. }
  8987. }
  8988. if (lookahead >= uc->opts.file_format_lookahead) {
  8989. break;
  8990. } else if (lookahead < SIZE_MAX / 2) {
  8991. lookahead = ufbxi_min_sz(lookahead * 2, uc->opts.file_format_lookahead);
  8992. } else {
  8993. lookahead = SIZE_MAX;
  8994. }
  8995. }
  8996. ufbxi_check(ufbxi_resume_progress(uc));
  8997. }
  8998. if (format == UFBX_FILE_FORMAT_UNKNOWN && !uc->opts.no_format_from_extension) {
  8999. if (uc->opts.filename.length > 0) {
  9000. ufbx_string extension = uc->opts.filename;
  9001. for (size_t i = extension.length; i > 0; i--) {
  9002. if (extension.data[i - 1] == '.') {
  9003. extension.data += i - 1;
  9004. extension.length -= i - 1;
  9005. break;
  9006. }
  9007. }
  9008. if (ufbxi_match(&extension, "\\c\\.fbx")) {
  9009. format = UFBX_FILE_FORMAT_FBX;
  9010. } else if (ufbxi_match(&extension, "\\c\\.obj")) {
  9011. format = UFBX_FILE_FORMAT_OBJ;
  9012. } else if (ufbxi_match(&extension, "\\c\\.mtl")) {
  9013. format = UFBX_FILE_FORMAT_MTL;
  9014. }
  9015. }
  9016. }
  9017. ufbxi_check_msg(format != UFBX_FILE_FORMAT_UNKNOWN, "Unrecognized file format");
  9018. uc->scene.metadata.file_format = format;
  9019. return 1;
  9020. }
  9021. ufbxi_nodiscard static ufbxi_noinline int ufbxi_begin_parse(ufbxi_context *uc)
  9022. {
  9023. const char *header = ufbxi_peek_bytes(uc, UFBXI_BINARY_HEADER_SIZE);
  9024. ufbxi_check(header);
  9025. // If the file starts with the binary magic parse it as binary, otherwise
  9026. // treat it as an ASCII file.
  9027. if (!memcmp(header, ufbxi_binary_magic, UFBXI_BINARY_MAGIC_SIZE)) {
  9028. // The byte after the magic indicates endianness
  9029. char endian = header[UFBXI_BINARY_MAGIC_SIZE + 0];
  9030. uc->file_big_endian = endian != 0;
  9031. // Read the version directly from the header
  9032. const char *version_word = header + UFBXI_BINARY_MAGIC_SIZE + 1;
  9033. if (uc->file_big_endian) {
  9034. version_word = ufbxi_swap_endian(uc, version_word, 1, 4);
  9035. ufbxi_check(version_word);
  9036. }
  9037. uc->version = ufbxi_read_u32(version_word);
  9038. // This is quite probably an FBX file..
  9039. uc->sure_fbx = true;
  9040. ufbxi_consume_bytes(uc, UFBXI_BINARY_HEADER_SIZE);
  9041. } else {
  9042. uc->from_ascii = true;
  9043. // Use the current read buffer as the initial parse buffer
  9044. memset(&uc->ascii, 0, sizeof(uc->ascii));
  9045. uc->ascii.src = uc->data;
  9046. uc->ascii.src_yield = uc->data + uc->yield_size;
  9047. uc->ascii.src_end = uc->data + uc->data_size + uc->yield_size;
  9048. // Initialize the first token
  9049. ufbxi_check(ufbxi_ascii_next_token(uc, &uc->ascii.token));
  9050. // Default to version 7400 if not found in header
  9051. if (uc->version > 0) {
  9052. uc->sure_fbx = true;
  9053. } else {
  9054. if (!uc->opts.strict) uc->version = 7400;
  9055. ufbxi_check_msg(uc->version > 0, "Not an FBX file");
  9056. }
  9057. }
  9058. return 1;
  9059. }
  9060. ufbxi_nodiscard static int ufbxi_parse_toplevel_child_imp(ufbxi_context *uc, ufbxi_parse_state state, ufbxi_buf *buf, bool *p_end)
  9061. {
  9062. if (uc->from_ascii) {
  9063. ufbxi_check(ufbxi_ascii_parse_node(uc, 0, state, p_end, buf, true));
  9064. } else {
  9065. ufbxi_check(ufbxi_binary_parse_node(uc, 0, state, p_end, buf, true));
  9066. }
  9067. return 1;
  9068. }
  9069. ufbxi_nodiscard ufbxi_noinline static int ufbxi_parse_toplevel(ufbxi_context *uc, const char *name)
  9070. {
  9071. ufbxi_for(ufbxi_node, node, uc->top_nodes, uc->top_nodes_len) {
  9072. if (node->name == name) {
  9073. uc->top_node = node;
  9074. uc->top_child_index = 0;
  9075. return 1;
  9076. }
  9077. }
  9078. // Reached end and not found in cache
  9079. if (uc->parsed_to_end) {
  9080. uc->top_node = NULL;
  9081. uc->top_child_index = 0;
  9082. return 1;
  9083. }
  9084. for (;;) {
  9085. // Parse the next top-level node
  9086. bool end = false;
  9087. if (uc->from_ascii) {
  9088. ufbxi_check(ufbxi_ascii_parse_node(uc, 0, UFBXI_PARSE_ROOT, &end, &uc->tmp, false));
  9089. } else {
  9090. ufbxi_check(ufbxi_binary_parse_node(uc, 0, UFBXI_PARSE_ROOT, &end, &uc->tmp, false));
  9091. }
  9092. // Top-level node not found
  9093. if (end) {
  9094. uc->top_node = NULL;
  9095. uc->top_child_index = 0;
  9096. uc->parsed_to_end = true;
  9097. if (uc->opts.retain_dom) {
  9098. ufbxi_check(ufbxi_retain_toplevel(uc, NULL));
  9099. }
  9100. // Not needed anymore
  9101. ufbxi_buf_free(&uc->tmp_parse);
  9102. return 1;
  9103. }
  9104. uc->top_nodes_len++;
  9105. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->top_nodes, &uc->top_nodes_cap, uc->top_nodes_len));
  9106. ufbxi_node *node = &uc->top_nodes[uc->top_nodes_len - 1];
  9107. ufbxi_pop(&uc->tmp_stack, ufbxi_node, 1, node);
  9108. if (uc->opts.retain_dom) {
  9109. ufbxi_check(ufbxi_retain_toplevel(uc, node));
  9110. }
  9111. // Return if we parsed the right one
  9112. if (node->name == name) {
  9113. uc->top_node = node;
  9114. uc->top_child_index = SIZE_MAX;
  9115. return 1;
  9116. }
  9117. // If not we need to parse all the children of the node for later
  9118. uint32_t num_children = 0;
  9119. ufbxi_parse_state state = ufbxi_update_parse_state(UFBXI_PARSE_ROOT, node->name);
  9120. if (uc->has_next_child) {
  9121. for (;;) {
  9122. ufbxi_check(ufbxi_parse_toplevel_child_imp(uc, state, &uc->tmp, &end));
  9123. if (end) break;
  9124. num_children++;
  9125. }
  9126. }
  9127. node->num_children = num_children;
  9128. node->children = ufbxi_push_pop(&uc->tmp, &uc->tmp_stack, ufbxi_node, num_children);
  9129. ufbxi_check(node->children);
  9130. if (uc->opts.retain_dom) {
  9131. for (size_t i = 0; i < num_children; i++) {
  9132. ufbxi_check(ufbxi_retain_toplevel_child(uc, &node->children[i]));
  9133. }
  9134. }
  9135. }
  9136. }
  9137. ufbxi_nodiscard ufbxi_noinline static int ufbxi_parse_toplevel_child(ufbxi_context *uc, ufbxi_node **p_node, ufbxi_buf *tmp_buf)
  9138. {
  9139. // Top-level node not found
  9140. if (!uc->top_node) {
  9141. *p_node = NULL;
  9142. return 1;
  9143. }
  9144. if (uc->top_child_index == SIZE_MAX) {
  9145. // Parse children on demand
  9146. if (!tmp_buf) {
  9147. ufbxi_buf_clear(&uc->tmp_parse);
  9148. }
  9149. bool end = false;
  9150. ufbxi_parse_state state = ufbxi_update_parse_state(UFBXI_PARSE_ROOT, uc->top_node->name);
  9151. ufbxi_check(ufbxi_parse_toplevel_child_imp(uc, state, tmp_buf ? tmp_buf : &uc->tmp_parse, &end));
  9152. if (end) {
  9153. *p_node = NULL;
  9154. } else {
  9155. // Parse to either reused `uc->top_child` or push if retaining to `tmp_buf`.
  9156. ufbxi_node *dst = &uc->top_child;
  9157. if (tmp_buf) {
  9158. dst = ufbxi_push_zero(tmp_buf, ufbxi_node, 1);
  9159. ufbxi_check(dst);
  9160. }
  9161. ufbxi_pop(&uc->tmp_stack, ufbxi_node, 1, dst);
  9162. *p_node = dst;
  9163. if (uc->opts.retain_dom) {
  9164. ufbxi_check(ufbxi_retain_toplevel_child(uc, dst));
  9165. }
  9166. }
  9167. } else {
  9168. // Iterate already parsed nodes
  9169. size_t child_index = uc->top_child_index;
  9170. if (child_index == uc->top_node->num_children) {
  9171. *p_node = NULL;
  9172. } else {
  9173. uc->top_child_index++;
  9174. *p_node = &uc->top_node->children[child_index];
  9175. }
  9176. }
  9177. return 1;
  9178. }
  9179. ufbxi_nodiscard ufbxi_noinline static int ufbxi_parse_legacy_toplevel(ufbxi_context *uc)
  9180. {
  9181. ufbx_assert(uc->top_nodes_len == 0);
  9182. bool end = false;
  9183. if (uc->from_ascii) {
  9184. ufbxi_check(ufbxi_ascii_parse_node(uc, 0, UFBXI_PARSE_ROOT, &end, &uc->tmp, true));
  9185. } else {
  9186. ufbxi_check(ufbxi_binary_parse_node(uc, 0, UFBXI_PARSE_ROOT, &end, &uc->tmp, true));
  9187. }
  9188. // Top-level node not found
  9189. if (end) {
  9190. uc->top_node = NULL;
  9191. uc->top_child_index = 0;
  9192. uc->parsed_to_end = true;
  9193. return 1;
  9194. }
  9195. ufbxi_pop(&uc->tmp_stack, ufbxi_node, 1, &uc->legacy_node);
  9196. uc->top_child_index = 0;
  9197. uc->top_node = &uc->legacy_node;
  9198. if (uc->opts.retain_dom) {
  9199. ufbxi_check(ufbxi_retain_toplevel(uc, &uc->legacy_node));
  9200. }
  9201. return 1;
  9202. }
  9203. // -- Setup
  9204. ufbxi_nodiscard static ufbxi_noinline int ufbxi_load_strings(ufbxi_context *uc)
  9205. {
  9206. #if defined(UFBX_REGRESSION)
  9207. ufbx_string reg_prev = ufbx_empty_string;
  9208. #endif
  9209. // Push all the global 'ufbxi_*' strings into the pool without copying them
  9210. // This allows us to compare name pointers to the global values
  9211. ufbxi_for(const ufbx_string, str, ufbxi_strings, ufbxi_arraycount(ufbxi_strings)) {
  9212. #if defined(UFBX_REGRESSION)
  9213. ufbx_assert(strlen(str->data) == str->length);
  9214. ufbx_assert(ufbxi_str_less(reg_prev, *str));
  9215. reg_prev = *str;
  9216. #endif
  9217. ufbxi_check(ufbxi_push_string_imp(&uc->string_pool, str->data, str->length, NULL, false, true));
  9218. }
  9219. return 1;
  9220. }
  9221. typedef struct {
  9222. const char *name;
  9223. ufbx_prop_type type;
  9224. } ufbxi_prop_type_name;
  9225. static const ufbxi_prop_type_name ufbxi_prop_type_names[] = {
  9226. { "Boolean", UFBX_PROP_BOOLEAN },
  9227. { "bool", UFBX_PROP_BOOLEAN },
  9228. { "Bool", UFBX_PROP_BOOLEAN },
  9229. { "Integer", UFBX_PROP_INTEGER },
  9230. { "int", UFBX_PROP_INTEGER },
  9231. { "enum", UFBX_PROP_INTEGER },
  9232. { "Visibility", UFBX_PROP_INTEGER },
  9233. { "Visibility Inheritance", UFBX_PROP_INTEGER },
  9234. { "KTime", UFBX_PROP_INTEGER },
  9235. { "Number", UFBX_PROP_NUMBER },
  9236. { "double", UFBX_PROP_NUMBER },
  9237. { "Real", UFBX_PROP_NUMBER },
  9238. { "Float", UFBX_PROP_NUMBER },
  9239. { "Intensity", UFBX_PROP_NUMBER },
  9240. { "Vector", UFBX_PROP_VECTOR },
  9241. { "Vector3D", UFBX_PROP_VECTOR },
  9242. { "Color", UFBX_PROP_COLOR },
  9243. { "ColorAndAlpha", UFBX_PROP_COLOR_WITH_ALPHA },
  9244. { "ColorRGB", UFBX_PROP_COLOR },
  9245. { "String", UFBX_PROP_STRING },
  9246. { "KString", UFBX_PROP_STRING },
  9247. { "object", UFBX_PROP_STRING },
  9248. { "DateTime", UFBX_PROP_DATE_TIME },
  9249. { "Lcl Translation", UFBX_PROP_TRANSLATION },
  9250. { "Lcl Rotation", UFBX_PROP_ROTATION },
  9251. { "Lcl Scaling", UFBX_PROP_SCALING },
  9252. { "Distance", UFBX_PROP_DISTANCE },
  9253. { "Compound", UFBX_PROP_COMPOUND },
  9254. { "Blob", UFBX_PROP_BLOB },
  9255. { "Reference", UFBX_PROP_REFERENCE },
  9256. };
  9257. static ufbx_prop_type ufbxi_get_prop_type(ufbxi_context *uc, const char *name)
  9258. {
  9259. uint32_t hash = ufbxi_hash_ptr(name);
  9260. ufbxi_prop_type_name *entry = ufbxi_map_find(&uc->prop_type_map, ufbxi_prop_type_name, hash, &name);
  9261. if (entry) {
  9262. return entry->type;
  9263. }
  9264. return UFBX_PROP_UNKNOWN;
  9265. }
  9266. static ufbxi_noinline ufbx_prop *ufbxi_find_prop_with_key(const ufbx_props *props, const char *name, uint32_t key)
  9267. {
  9268. do {
  9269. ufbx_prop *prop_data = props->props.data;
  9270. size_t begin = 0;
  9271. size_t end = props->props.count;
  9272. while (end - begin >= 16) {
  9273. size_t mid = (begin + end) >> 1;
  9274. const ufbx_prop *p = &prop_data[mid];
  9275. if (p->_internal_key < key) {
  9276. begin = mid + 1;
  9277. } else {
  9278. end = mid;
  9279. }
  9280. }
  9281. end = props->props.count;
  9282. for (; begin < end; begin++) {
  9283. const ufbx_prop *p = &prop_data[begin];
  9284. if (p->_internal_key > key) break;
  9285. if (p->name.data == name && (p->flags & UFBX_PROP_FLAG_NO_VALUE) == 0) {
  9286. return (ufbx_prop*)p;
  9287. }
  9288. }
  9289. props = props->defaults;
  9290. } while (props);
  9291. return NULL;
  9292. }
  9293. typedef struct {
  9294. const char *key;
  9295. ufbx_texture_file *file;
  9296. } ufbxi_texture_file_entry;
  9297. #define ufbxi_find_prop(props, name) ufbxi_find_prop_with_key((props), (name), \
  9298. ((uint32_t)(uint8_t)name[0] << 24u) | ((uint32_t)(uint8_t)name[1] << 16u) | \
  9299. ((uint32_t)(uint8_t)name[2] << 8u) | (uint32_t)(uint8_t)name[3])
  9300. static ufbxi_forceinline ufbx_real ufbxi_find_real(const ufbx_props *props, const char *name, ufbx_real def)
  9301. {
  9302. ufbx_prop *prop = ufbxi_find_prop(props, name);
  9303. if (prop) {
  9304. return prop->value_real;
  9305. } else {
  9306. return def;
  9307. }
  9308. }
  9309. static ufbxi_forceinline ufbx_vec3 ufbxi_find_vec3(const ufbx_props *props, const char *name, ufbx_real def_x, ufbx_real def_y, ufbx_real def_z)
  9310. {
  9311. ufbx_prop *prop = ufbxi_find_prop(props, name);
  9312. if (prop) {
  9313. return prop->value_vec3;
  9314. } else {
  9315. ufbx_vec3 def = { def_x, def_y, def_z };
  9316. return def;
  9317. }
  9318. }
  9319. static ufbxi_forceinline int64_t ufbxi_find_int(const ufbx_props *props, const char *name, int64_t def)
  9320. {
  9321. ufbx_prop *prop = ufbxi_find_prop(props, name);
  9322. if (prop) {
  9323. return prop->value_int;
  9324. } else {
  9325. return def;
  9326. }
  9327. }
  9328. static ufbxi_forceinline int64_t ufbxi_find_enum(const ufbx_props *props, const char *name, int64_t def, int64_t max_value)
  9329. {
  9330. ufbx_prop *prop = ufbxi_find_prop(props, name);
  9331. if (prop) {
  9332. int64_t value = prop->value_int;
  9333. if (value >= 0 && value <= max_value) {
  9334. return value;
  9335. } else {
  9336. return def;
  9337. }
  9338. } else {
  9339. return def;
  9340. }
  9341. }
  9342. ufbxi_noinline static bool ufbxi_matrix_all_zero(const ufbx_matrix *matrix)
  9343. {
  9344. for (size_t i = 0; i < 12; i++) {
  9345. if (matrix->v[i] != 0.0f) return false;
  9346. }
  9347. return true;
  9348. }
  9349. static ufbxi_forceinline bool ufbxi_is_vec3_zero(ufbx_vec3 v)
  9350. {
  9351. return (v.x == 0.0) & (v.y == 0.0) & (v.z == 0.0);
  9352. }
  9353. static ufbxi_forceinline bool ufbxi_is_vec4_zero(ufbx_vec4 v)
  9354. {
  9355. return (v.x == 0.0) & (v.y == 0.0) & (v.z == 0.0);
  9356. }
  9357. static ufbxi_forceinline bool ufbxi_is_vec3_one(ufbx_vec3 v)
  9358. {
  9359. return (v.x == 1.0) & (v.y == 1.0) & (v.z == 1.0);
  9360. }
  9361. static ufbxi_forceinline bool ufbxi_is_quat_identity(ufbx_quat v)
  9362. {
  9363. return (v.x == 0.0) & (v.y == 0.0) & (v.z == 0.0) & (v.w == 1.0);
  9364. }
  9365. static ufbxi_noinline bool ufbxi_is_transform_identity(const ufbx_transform *t)
  9366. {
  9367. return (bool)((int)ufbxi_is_vec3_zero(t->translation) & (int)ufbxi_is_quat_identity(t->rotation) & (int)ufbxi_is_vec3_one(t->scale));
  9368. }
  9369. static ufbxi_forceinline uint32_t ufbxi_get_name_key(const char *name, size_t len)
  9370. {
  9371. uint32_t key = 0;
  9372. if (len >= 4) {
  9373. key = (uint32_t)(uint8_t)name[0]<<24 | (uint32_t)(uint8_t)name[1]<<16
  9374. | (uint32_t)(uint8_t)name[2]<<8 | (uint32_t)(uint8_t)name[3];
  9375. } else {
  9376. for (size_t i = 0; i < 4; i++) {
  9377. key <<= 8;
  9378. if (i < len) key |= (uint8_t)name[i];
  9379. }
  9380. }
  9381. return key;
  9382. }
  9383. static ufbxi_forceinline uint32_t ufbxi_get_name_key_c(const char *name)
  9384. {
  9385. if (name[0] == '\0') return 0;
  9386. if (name[1] == '\0') return (uint32_t)(uint8_t)name[0]<<24;
  9387. if (name[2] == '\0') return (uint32_t)(uint8_t)name[0]<<24 | (uint32_t)(uint8_t)name[1]<<16;
  9388. return (uint32_t)(uint8_t)name[0]<<24 | (uint32_t)(uint8_t)name[1]<<16
  9389. | (uint32_t)(uint8_t)name[2]<<8 | (uint32_t)(uint8_t)name[3];
  9390. }
  9391. static ufbxi_forceinline bool ufbxi_name_key_less(ufbx_prop *prop, const char *data, size_t name_len, uint32_t key)
  9392. {
  9393. if (prop->_internal_key < key) return true;
  9394. if (prop->_internal_key > key) return false;
  9395. size_t prop_len = prop->name.length;
  9396. size_t len = ufbxi_min_sz(prop_len, name_len);
  9397. int cmp = memcmp(prop->name.data, data, len);
  9398. if (cmp != 0) return cmp < 0;
  9399. return prop_len < name_len;
  9400. }
  9401. static const char *const ufbxi_node_prop_names[] = {
  9402. "AxisLen",
  9403. "DefaultAttributeIndex",
  9404. "Freeze",
  9405. "GeometricRotation",
  9406. "GeometricScaling",
  9407. "GeometricTranslation",
  9408. "InheritType",
  9409. "LODBox",
  9410. "Lcl Rotation",
  9411. "Lcl Scaling",
  9412. "Lcl Translation",
  9413. "LookAtProperty",
  9414. "MaxDampRangeX",
  9415. "MaxDampRangeY",
  9416. "MaxDampRangeZ",
  9417. "MaxDampStrengthX",
  9418. "MaxDampStrengthY",
  9419. "MaxDampStrengthZ",
  9420. "MinDampRangeX",
  9421. "MinDampRangeY",
  9422. "MinDampRangeZ",
  9423. "MinDampStrengthX",
  9424. "MinDampStrengthY",
  9425. "MinDampStrengthZ",
  9426. "NegativePercentShapeSupport",
  9427. "PostRotation",
  9428. "PreRotation",
  9429. "PreferedAngleX",
  9430. "PreferedAngleY",
  9431. "PreferedAngleZ",
  9432. "QuaternionInterpolate",
  9433. "RotationActive",
  9434. "RotationMax",
  9435. "RotationMaxX",
  9436. "RotationMaxY",
  9437. "RotationMaxZ",
  9438. "RotationMin",
  9439. "RotationMinX",
  9440. "RotationMinY",
  9441. "RotationMinZ",
  9442. "RotationOffset",
  9443. "RotationOrder",
  9444. "RotationPivot",
  9445. "RotationSpaceForLimitOnly",
  9446. "RotationStiffnessX",
  9447. "RotationStiffnessY",
  9448. "RotationStiffnessZ",
  9449. "ScalingActive",
  9450. "ScalingMax",
  9451. "ScalingMaxX",
  9452. "ScalingMaxY",
  9453. "ScalingMaxZ",
  9454. "ScalingMin",
  9455. "ScalingMinX",
  9456. "ScalingMinY",
  9457. "ScalingMinZ",
  9458. "ScalingOffset",
  9459. "ScalingPivot",
  9460. "Show",
  9461. "TranslationActive",
  9462. "TranslationMax",
  9463. "TranslationMaxX",
  9464. "TranslationMaxY",
  9465. "TranslationMaxZ",
  9466. "TranslationMin",
  9467. "TranslationMinX",
  9468. "TranslationMinY",
  9469. "TranslationMinZ",
  9470. "UpVectorProperty",
  9471. "Visibility Inheritance",
  9472. "Visibility",
  9473. "notes",
  9474. };
  9475. ufbxi_nodiscard static ufbxi_noinline int ufbxi_init_node_prop_names(ufbxi_context *uc)
  9476. {
  9477. ufbxi_check(ufbxi_map_grow(&uc->node_prop_set, const char*, ufbxi_arraycount(ufbxi_node_prop_names)));
  9478. for (size_t i = 0; i < ufbxi_arraycount(ufbxi_node_prop_names); i++) {
  9479. const char *name = ufbxi_node_prop_names[i];
  9480. const char *pooled = ufbxi_push_string_imp(&uc->string_pool, name, strlen(name), NULL, false, true);
  9481. ufbxi_check(pooled);
  9482. uint32_t hash = ufbxi_hash_ptr(pooled);
  9483. const char **entry = ufbxi_map_insert(&uc->node_prop_set, const char*, hash, &pooled);
  9484. ufbxi_check(entry);
  9485. *entry = pooled;
  9486. }
  9487. return 1;
  9488. }
  9489. static bool ufbxi_is_node_property(ufbxi_context *uc, const char *name)
  9490. {
  9491. // You need to call `ufbxi_init_node_prop_names()` before calling this
  9492. ufbx_assert(uc->node_prop_set.size > 0);
  9493. uint32_t hash = ufbxi_hash_ptr(name);
  9494. const char **entry = ufbxi_map_find(&uc->node_prop_set, const char*, hash, &name);
  9495. return entry != NULL;
  9496. }
  9497. ufbxi_nodiscard static ufbxi_noinline int ufbxi_load_maps(ufbxi_context *uc)
  9498. {
  9499. ufbxi_check(ufbxi_map_grow(&uc->prop_type_map, ufbxi_prop_type_name, ufbxi_arraycount(ufbxi_prop_type_names)));
  9500. ufbxi_for(const ufbxi_prop_type_name, name, ufbxi_prop_type_names, ufbxi_arraycount(ufbxi_prop_type_names)) {
  9501. const char *pooled = ufbxi_push_string_imp(&uc->string_pool, name->name, strlen(name->name), NULL, false, true);
  9502. ufbxi_check(pooled);
  9503. uint32_t hash = ufbxi_hash_ptr(pooled);
  9504. ufbxi_prop_type_name *entry = ufbxi_map_insert(&uc->prop_type_map, ufbxi_prop_type_name, hash, &pooled);
  9505. ufbxi_check(entry);
  9506. entry->type = name->type;
  9507. entry->name = pooled;
  9508. }
  9509. return 1;
  9510. }
  9511. // -- Reading the parsed data
  9512. ufbxi_noinline static void ufbxi_decode_base64(char *dst, const char *src, size_t src_length)
  9513. {
  9514. uint8_t table[256] = { 0 };
  9515. for (char c = 'A'; c <= 'Z'; c++) table[(size_t)c] = (uint8_t)(c - 'A');
  9516. for (char c = 'a'; c <= 'z'; c++) table[(size_t)c] = (uint8_t)(26 + (c - 'a'));
  9517. for (char c = '0'; c <= '9'; c++) table[(size_t)c] = (uint8_t)(52 + (c - '0'));
  9518. table[(size_t)'+'] = 62;
  9519. table[(size_t)'/'] = 63;
  9520. for (size_t i = 0; i + 4 <= src_length; i += 4) {
  9521. uint32_t a = table[(size_t)(uint8_t)src[i + 0]];
  9522. uint32_t b = table[(size_t)(uint8_t)src[i + 1]];
  9523. uint32_t c = table[(size_t)(uint8_t)src[i + 2]];
  9524. uint32_t d = table[(size_t)(uint8_t)src[i + 3]];
  9525. dst[0] = (char)(uint8_t)(a << 2 | b >> 4);
  9526. dst[1] = (char)(uint8_t)(b << 4 | c >> 2);
  9527. dst[2] = (char)(uint8_t)(c << 6 | d);
  9528. dst += 3;
  9529. }
  9530. }
  9531. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_embedded_blob(ufbxi_context *uc, ufbx_blob *dst_blob, ufbxi_node *node)
  9532. {
  9533. if (!node) return 1;
  9534. ufbxi_value_array *content_arr = ufbxi_get_array(node, 'C');
  9535. if (content_arr && content_arr->size > 0) {
  9536. ufbx_string content;
  9537. size_t num_parts = content_arr->size;
  9538. ufbx_string *parts = (ufbx_string*)content_arr->data;
  9539. if (num_parts == 1) {
  9540. content = parts[0];
  9541. } else {
  9542. size_t total_size = 0;
  9543. ufbxi_for(ufbx_string, part, parts, num_parts) {
  9544. total_size += part->length;
  9545. }
  9546. ufbxi_buf *dst_buf = uc->from_ascii ? &uc->tmp_parse : &uc->result;
  9547. char *dst = ufbxi_push(dst_buf, char, total_size);
  9548. ufbxi_check(dst);
  9549. content.data = dst;
  9550. content.length = total_size;
  9551. ufbxi_for(ufbx_string, part, parts, num_parts) {
  9552. memcpy(dst, part->data, part->length);
  9553. dst += part->length;
  9554. }
  9555. }
  9556. if (uc->from_ascii) {
  9557. if (content.length % 4 == 0) {
  9558. size_t padding = 0;
  9559. while (padding < 2 && padding < content.length && content.data[content.length - 1 - padding] == '=') {
  9560. padding++;
  9561. }
  9562. dst_blob->size = content.length / 4 * 3 - padding;
  9563. dst_blob->data = ufbxi_push(&uc->result, char, dst_blob->size + 3);
  9564. ufbxi_check(dst_blob->data);
  9565. ufbxi_decode_base64((char*)dst_blob->data, content.data, content.length);
  9566. }
  9567. } else {
  9568. dst_blob->data = content.data;
  9569. dst_blob->size = content.length;
  9570. }
  9571. }
  9572. return 1;
  9573. }
  9574. ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_property(ufbxi_context *uc, ufbxi_node *node, ufbx_prop *prop, int version)
  9575. {
  9576. const char *type_str = NULL, *subtype_str = NULL;
  9577. ufbxi_check(ufbxi_get_val2(node, "SC", &prop->name, (char**)&type_str));
  9578. uint32_t val_ix = 2;
  9579. if (version == 70) {
  9580. ufbxi_check(ufbxi_get_val_at(node, val_ix++, 'C', (char**)&subtype_str));
  9581. }
  9582. uint32_t flags = 0;
  9583. prop->_internal_key = ufbxi_get_name_key(prop->name.data, prop->name.length);
  9584. ufbx_string flags_str;
  9585. if (ufbxi_get_val_at(node, val_ix++, 'S', &flags_str)) {
  9586. for (size_t i = 0; i < flags_str.length; i++) {
  9587. char next = i + 1 < flags_str.length ? flags_str.data[i + 1] : '0';
  9588. switch (flags_str.data[i]) {
  9589. case 'A': flags |= UFBX_PROP_FLAG_ANIMATABLE; break;
  9590. case 'U': flags |= UFBX_PROP_FLAG_USER_DEFINED; break;
  9591. case 'H': flags |= UFBX_PROP_FLAG_HIDDEN; break;
  9592. case 'L': flags |= ((uint32_t)(next - '0') & 0xf) << 4; break; // UFBX_PROP_FLAG_LOCK_*
  9593. case 'M': flags |= ((uint32_t)(next - '0') & 0xf) << 8; break; // UFBX_PROP_FLAG_MUTE_*
  9594. default: break; // Ignore unknown flags
  9595. }
  9596. }
  9597. }
  9598. prop->type = ufbxi_get_prop_type(uc, type_str);
  9599. if (prop->type == UFBX_PROP_UNKNOWN && subtype_str) {
  9600. prop->type = ufbxi_get_prop_type(uc, subtype_str);
  9601. }
  9602. if (ufbxi_get_val_at(node, val_ix, 'L', &prop->value_int)) {
  9603. flags |= (uint32_t)UFBX_PROP_FLAG_VALUE_INT;
  9604. }
  9605. size_t real_ix;
  9606. for (real_ix = 0; real_ix < 4; real_ix++) {
  9607. if (!ufbxi_get_val_at(node, val_ix + real_ix, 'R', &prop->value_real_arr[real_ix])) break;
  9608. }
  9609. if (real_ix > 0) {
  9610. flags |= (uint32_t)UFBX_PROP_FLAG_VALUE_REAL << (real_ix - 1);
  9611. }
  9612. // Distance properties have a string unit _after_ the real value, eg. `10, "cm"`
  9613. if (prop->type == UFBX_PROP_DISTANCE) {
  9614. val_ix++;
  9615. }
  9616. if (ufbxi_get_val_at(node, val_ix, 'S', &prop->value_str)) {
  9617. if (prop->value_str.length > 0) {
  9618. ufbxi_ignore(ufbxi_get_val_at(node, val_ix, 'b', &prop->value_blob));
  9619. }
  9620. flags |= (uint32_t)UFBX_PROP_FLAG_VALUE_STR;
  9621. } else {
  9622. prop->value_str = ufbx_empty_string;
  9623. }
  9624. // Very unlikely, seems to only exist in some "non standard" FBX files
  9625. if (node->num_children > 0) {
  9626. ufbxi_node *binary = ufbxi_find_child(node, ufbxi_BinaryData);
  9627. ufbxi_check(ufbxi_read_embedded_blob(uc, &prop->value_blob, binary));
  9628. flags |= (uint32_t)UFBX_PROP_FLAG_VALUE_BLOB;
  9629. }
  9630. prop->flags = (ufbx_prop_flags)flags;
  9631. return 1;
  9632. }
  9633. static ufbxi_forceinline bool ufbxi_prop_less(ufbx_prop *a, ufbx_prop *b)
  9634. {
  9635. if (a->_internal_key < b->_internal_key) return true;
  9636. if (a->_internal_key > b->_internal_key) return false;
  9637. return strcmp(a->name.data, b->name.data) < 0;
  9638. }
  9639. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_properties(ufbxi_context *uc, ufbx_prop *props, size_t count)
  9640. {
  9641. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_prop)));
  9642. ufbxi_macro_stable_sort(ufbx_prop, 32, props, uc->tmp_arr, count, ( ufbxi_prop_less(a, b) ));
  9643. return 1;
  9644. }
  9645. ufbxi_noinline static void ufbxi_deduplicate_properties(ufbx_prop_list *list)
  9646. {
  9647. if (list->count >= 2) {
  9648. ufbx_prop *ps = list->data;
  9649. size_t dst = 0, src = 0, end = list->count;
  9650. while (src < end) {
  9651. if (src + 1 < end && ps[src].name.data == ps[src + 1].name.data) {
  9652. src++;
  9653. } else if (dst != src) {
  9654. ps[dst++] = ps[src++];
  9655. } else {
  9656. dst++; src++;
  9657. }
  9658. }
  9659. list->count = dst;
  9660. }
  9661. }
  9662. ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_properties(ufbxi_context *uc, ufbxi_node *parent, ufbx_props *props)
  9663. {
  9664. props->defaults = NULL;
  9665. int version = 70;
  9666. ufbxi_node *node = ufbxi_find_child(parent, ufbxi_Properties70);
  9667. if (!node) {
  9668. node = ufbxi_find_child(parent, ufbxi_Properties60);
  9669. if (!node) {
  9670. // No properties found, not an error
  9671. props->props.data = NULL;
  9672. props->props.count = 0;
  9673. return 1;
  9674. }
  9675. version = 60;
  9676. }
  9677. props->props.data = ufbxi_push_zero(&uc->result, ufbx_prop, node->num_children);
  9678. props->props.count = node->num_children;
  9679. ufbxi_check(props->props.data);
  9680. for (size_t i = 0; i < props->props.count; i++) {
  9681. ufbxi_check(ufbxi_read_property(uc, &node->children[i], &props->props.data[i], version));
  9682. }
  9683. ufbxi_check(ufbxi_sort_properties(uc, props->props.data, props->props.count));
  9684. ufbxi_deduplicate_properties(&props->props);
  9685. return 1;
  9686. }
  9687. ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_thumbnail(ufbxi_context *uc, ufbxi_node *node, ufbx_thumbnail *thumbnail)
  9688. {
  9689. ufbxi_check(ufbxi_read_properties(uc, node, &thumbnail->props));
  9690. int64_t custom_width = ufbx_find_int(&thumbnail->props, "CustomWidth", 0);
  9691. int64_t custom_height = ufbx_find_int(&thumbnail->props, "CustomHeight", 0);
  9692. int32_t format;
  9693. ufbxi_node *format_node = ufbxi_find_child_strcmp(node, "Format");
  9694. if (format_node && ufbxi_get_val1(format_node, "I", &format)) {
  9695. if (format >= 0 && format + 1 < UFBX_THUMBNAIL_FORMAT_COUNT) {
  9696. thumbnail->format = (ufbx_thumbnail_format)(format + 1);
  9697. }
  9698. }
  9699. int32_t size;
  9700. if (ufbxi_find_val1(node, ufbxi_Size, "I", &size)) {
  9701. if (size > 0) {
  9702. thumbnail->width = (uint32_t)size;
  9703. thumbnail->height = (uint32_t)size;
  9704. } else if (size < 0 && custom_width > 0 && custom_height > 0) {
  9705. thumbnail->width = (uint32_t)custom_width;
  9706. thumbnail->height = (uint32_t)custom_height;
  9707. }
  9708. }
  9709. ufbxi_value_array *data_arr = ufbxi_find_array(node, ufbxi_ImageData, 'c');
  9710. if (data_arr) {
  9711. thumbnail->data.data = data_arr->data;
  9712. thumbnail->data.size = data_arr->size;
  9713. }
  9714. return 1;
  9715. }
  9716. ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_scene_info(ufbxi_context *uc, ufbxi_node *node)
  9717. {
  9718. ufbxi_check(ufbxi_read_properties(uc, node, &uc->scene.metadata.scene_props));
  9719. ufbxi_node *thumbnail = ufbxi_find_child(node, ufbxi_Thumbnail);
  9720. if (thumbnail) {
  9721. ufbxi_check(ufbxi_read_thumbnail(uc, thumbnail, &uc->scene.metadata.thumbnail));
  9722. }
  9723. return 1;
  9724. }
  9725. ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_header_extension(ufbxi_context *uc)
  9726. {
  9727. // TODO: Read TCDefinition and adjust timestamps
  9728. uc->ktime_sec = 46186158000;
  9729. uc->ktime_sec_double = (double)uc->ktime_sec;
  9730. for (;;) {
  9731. ufbxi_node *child;
  9732. ufbxi_check(ufbxi_parse_toplevel_child(uc, &child, NULL));
  9733. if (!child) break;
  9734. if (child->name == ufbxi_Creator) {
  9735. ufbxi_ignore(ufbxi_get_val1(child, "S", &uc->scene.metadata.creator));
  9736. }
  9737. if (uc->version < 6000 && child->name == ufbxi_FBXVersion) {
  9738. int32_t version;
  9739. if (ufbxi_get_val1(child, "I", &version)) {
  9740. if (version > 0 && version < 6000 && (uint32_t)version > uc->version) {
  9741. uc->version = (uint32_t)version;
  9742. }
  9743. }
  9744. }
  9745. if (child->name == ufbxi_SceneInfo) {
  9746. ufbxi_check(ufbxi_read_scene_info(uc, child));
  9747. }
  9748. }
  9749. return 1;
  9750. }
  9751. static bool ufbxi_match_version_string(const char *fmt, ufbx_string str, uint32_t *p_version)
  9752. {
  9753. size_t num_ix = 0;
  9754. size_t pos = 0;
  9755. while (*fmt) {
  9756. char c = *fmt++;
  9757. if (c >= 'a' && c <= 'z') {
  9758. if (pos >= str.length) return false;
  9759. char s = str.data[pos];
  9760. if (s != c && (int)s + (int)('a' - 'A') != (int)c) return false;
  9761. pos++;
  9762. } else if (c == ' ') {
  9763. while (pos < str.length) {
  9764. char s = str.data[pos];
  9765. if (s != ' ' && s != '\t') break;
  9766. pos++;
  9767. }
  9768. } else if (c == '-') {
  9769. while (pos < str.length) {
  9770. char s = str.data[pos];
  9771. if (s == '-') break;
  9772. pos++;
  9773. }
  9774. if (pos >= str.length) return false;
  9775. pos++;
  9776. } else if (c == '/' || c == '.' || c == '(' || c == ')') {
  9777. if (pos >= str.length) return false;
  9778. if (str.data[pos] != c) return false;
  9779. pos++;
  9780. } else if (c == '?') {
  9781. uint32_t num = 0;
  9782. size_t len = 0;
  9783. while (pos < str.length) {
  9784. char s = str.data[pos];
  9785. if (!(s >= '0' && s <= '9')) break;
  9786. num = num*10 + (uint32_t)(s - '0');
  9787. pos++;
  9788. len++;
  9789. }
  9790. if (len == 0) return false;
  9791. p_version[num_ix++] = num;
  9792. } else {
  9793. ufbxi_unreachable("Unhandled match character");
  9794. }
  9795. }
  9796. return true;
  9797. }
  9798. ufbxi_nodiscard static int ufbxi_match_exporter(ufbxi_context *uc)
  9799. {
  9800. ufbx_string creator = uc->scene.metadata.creator;
  9801. uint32_t version[3] = { 0 };
  9802. if (ufbxi_match_version_string("blender-- ?.?.?", creator, version)) {
  9803. uc->exporter = UFBX_EXPORTER_BLENDER_BINARY;
  9804. uc->exporter_version = ufbx_pack_version(version[0], version[1], version[2]);
  9805. } else if (ufbxi_match_version_string("blender- ?.?", creator, version)) {
  9806. uc->exporter = UFBX_EXPORTER_BLENDER_BINARY;
  9807. uc->exporter_version = ufbx_pack_version(version[0], version[1], 0);
  9808. } else if (ufbxi_match_version_string("blender version ?.?", creator, version)) {
  9809. uc->exporter = UFBX_EXPORTER_BLENDER_ASCII;
  9810. uc->exporter_version = ufbx_pack_version(version[0], version[1], 0);
  9811. } else if (ufbxi_match_version_string("fbx sdk/fbx plugins version ?.?", creator, version)) {
  9812. uc->exporter = UFBX_EXPORTER_FBX_SDK;
  9813. uc->exporter_version = ufbx_pack_version(version[0], version[1], 0);
  9814. } else if (ufbxi_match_version_string("fbx sdk/fbx plugins build ?", creator, version)) {
  9815. uc->exporter = UFBX_EXPORTER_FBX_SDK;
  9816. uc->exporter_version = ufbx_pack_version(version[0]/10000u, version[0]/100u%100u, version[0]%100u);
  9817. } else if (ufbxi_match_version_string("motionbuilder version ?.?", creator, version)) {
  9818. uc->exporter = UFBX_EXPORTER_MOTION_BUILDER;
  9819. uc->exporter_version = ufbx_pack_version(version[0], version[1], 0);
  9820. } else if (ufbxi_match_version_string("motionbuilder/mocap/online version ?.?", creator, version)) {
  9821. uc->exporter = UFBX_EXPORTER_MOTION_BUILDER;
  9822. uc->exporter_version = ufbx_pack_version(version[0], version[1], 0);
  9823. }
  9824. uc->scene.metadata.exporter = uc->exporter;
  9825. uc->scene.metadata.exporter_version = uc->exporter_version;
  9826. // Un-detect the exporter in `ufbxi_context` to disable special cases
  9827. if (uc->opts.disable_quirks) {
  9828. uc->exporter = UFBX_EXPORTER_UNKNOWN;
  9829. uc->exporter_version = 0;
  9830. }
  9831. return 1;
  9832. }
  9833. ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_document(ufbxi_context *uc)
  9834. {
  9835. bool found_root_id = 0;
  9836. for (;;) {
  9837. ufbxi_node *child;
  9838. ufbxi_check(ufbxi_parse_toplevel_child(uc, &child, NULL));
  9839. if (!child) break;
  9840. if (child->name == ufbxi_Document && !found_root_id) {
  9841. // Post-7000: Try to find the first document node and root ID.
  9842. // TODO: Multiple documents / roots?
  9843. if (ufbxi_find_val1(child, ufbxi_RootNode, "L", &uc->root_id)) {
  9844. found_root_id = true;
  9845. }
  9846. }
  9847. }
  9848. return 1;
  9849. }
  9850. ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_definitions(ufbxi_context *uc)
  9851. {
  9852. for (;;) {
  9853. ufbxi_node *object;
  9854. ufbxi_check(ufbxi_parse_toplevel_child(uc, &object, NULL));
  9855. if (!object) break;
  9856. if (object->name != ufbxi_ObjectType) continue;
  9857. ufbxi_template *tmpl = ufbxi_push_zero(&uc->tmp_stack, ufbxi_template, 1);
  9858. uc->num_templates++;
  9859. ufbxi_check(tmpl);
  9860. ufbxi_check(ufbxi_get_val1(object, "C", (char**)&tmpl->type));
  9861. // Pre-7000 FBX versions don't have property templates, they just have
  9862. // the object counts by themselves.
  9863. ufbxi_node *props = ufbxi_find_child(object, ufbxi_PropertyTemplate);
  9864. if (props) {
  9865. ufbxi_check(ufbxi_get_val1(props, "S", &tmpl->sub_type));
  9866. // Remove the "Fbx" prefix from sub-types, remember to re-intern!
  9867. if (tmpl->sub_type.length > 3 && !strncmp(tmpl->sub_type.data, "Fbx", 3)) {
  9868. tmpl->sub_type.data += 3;
  9869. tmpl->sub_type.length -= 3;
  9870. // HACK: LOD groups use LODGroup for Template, LodGroup for Object?
  9871. if (tmpl->sub_type.length == 8 && !memcmp(tmpl->sub_type.data, "LODGroup", 8)) {
  9872. tmpl->sub_type.data = "LodGroup";
  9873. }
  9874. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &tmpl->sub_type, false));
  9875. }
  9876. ufbxi_check(ufbxi_read_properties(uc, props, &tmpl->props));
  9877. }
  9878. }
  9879. // TODO: Preserve only the `props` part of the templates
  9880. uc->templates = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbxi_template, uc->num_templates);
  9881. ufbxi_check(uc->templates);
  9882. return 1;
  9883. }
  9884. ufbxi_nodiscard static ufbx_props *ufbxi_find_template(ufbxi_context *uc, const char *name, const char *sub_type)
  9885. {
  9886. // TODO: Binary search
  9887. ufbxi_for(ufbxi_template, tmpl, uc->templates, uc->num_templates) {
  9888. if (tmpl->type == name) {
  9889. // Check that sub_type matches unless the type is Material, Model, AnimationStack, AnimationLayer.
  9890. // Those match to all sub-types.
  9891. if (tmpl->type != ufbxi_Material && tmpl->type != ufbxi_Model
  9892. && tmpl->type != ufbxi_AnimationStack && tmpl->type != ufbxi_AnimationLayer) {
  9893. if (tmpl->sub_type.data != sub_type) {
  9894. return NULL;
  9895. }
  9896. }
  9897. if (tmpl->props.props.count > 0) {
  9898. return &tmpl->props;
  9899. } else {
  9900. return NULL;
  9901. }
  9902. }
  9903. }
  9904. return NULL;
  9905. }
  9906. // Name ID categories
  9907. #define UFBXI_SYNTHETIC_ID_BIT UINT64_C(0x8000000000000000)
  9908. ufbx_static_assert(uptr_size, sizeof(uintptr_t) <= sizeof(uint64_t));
  9909. static ufbxi_forceinline uint64_t ufbxi_synthetic_id_from_pointer(const void *ptr)
  9910. {
  9911. uintptr_t uptr = (uintptr_t)ptr;
  9912. ufbx_assert((uptr & 0x1) == 0);
  9913. return (uptr >> 1u) | UFBXI_SYNTHETIC_ID_BIT;
  9914. }
  9915. static ufbxi_forceinline uint64_t ufbxi_synthetic_id_from_string(const char *str)
  9916. {
  9917. uintptr_t uptr = (uintptr_t)str;
  9918. uptr &= ~(uintptr_t)1;
  9919. return (uptr >> 1u) | UFBXI_SYNTHETIC_ID_BIT;
  9920. }
  9921. static ufbxi_noinline int ufbxi_push_synthetic_id(ufbxi_context *uc, uint64_t *p_dst)
  9922. {
  9923. void *ptr = ufbxi_push_size(&uc->tmp, 8, 1);
  9924. ufbxi_check(ptr);
  9925. *p_dst = ufbxi_synthetic_id_from_pointer(ptr);
  9926. return 1;
  9927. }
  9928. ufbxi_nodiscard ufbxi_noinline static int ufbxi_split_type_and_name(ufbxi_context *uc, ufbx_string type_and_name, ufbx_string *type, ufbx_string *name)
  9929. {
  9930. // Name and type are packed in a single property as Type::Name (in ASCII)
  9931. // or Name\x00\x01Type (in binary)
  9932. const char *sep = uc->from_ascii ? "::" : "\x00\x01";
  9933. size_t type_end = 2;
  9934. for (; type_end <= type_and_name.length; type_end++) {
  9935. const char *ch = type_and_name.data + type_end - 2;
  9936. if (ch[0] == sep[0] && ch[1] == sep[1]) break;
  9937. }
  9938. // ???: ASCII and binary store type and name in different order
  9939. if (type_end <= type_and_name.length) {
  9940. if (uc->from_ascii) {
  9941. name->data = type_and_name.data + type_end;
  9942. name->length = type_and_name.length - type_end;
  9943. type->data = type_and_name.data;
  9944. type->length = type_end - 2;
  9945. } else {
  9946. name->data = type_and_name.data;
  9947. name->length = type_end - 2;
  9948. type->data = type_and_name.data + type_end;
  9949. type->length = type_and_name.length - type_end;
  9950. }
  9951. } else {
  9952. *name = type_and_name;
  9953. type->data = ufbxi_empty_char;
  9954. type->length = 0;
  9955. }
  9956. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, type, false));
  9957. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, name, false));
  9958. return 1;
  9959. }
  9960. ufbxi_nodiscard ufbxi_noinline static int ufbxi_insert_fbx_id(ufbxi_context *uc, uint64_t fbx_id, uint32_t element_id)
  9961. {
  9962. uint32_t hash = ufbxi_hash64(fbx_id);
  9963. ufbxi_fbx_id_entry *entry = ufbxi_map_find(&uc->fbx_id_map, ufbxi_fbx_id_entry, hash, &fbx_id);
  9964. if (!entry) {
  9965. entry = ufbxi_map_insert(&uc->fbx_id_map, ufbxi_fbx_id_entry, hash, &fbx_id);
  9966. ufbxi_check(entry);
  9967. entry->fbx_id = fbx_id;
  9968. entry->element_id = element_id;
  9969. entry->user_id = 0;
  9970. } else {
  9971. ufbxi_check(ufbxi_warnf(UFBX_WARNING_DUPLICATE_OBJECT_ID, "Duplicate object ID"));
  9972. }
  9973. return 1;
  9974. }
  9975. static ufbxi_noinline ufbxi_fbx_id_entry *ufbxi_find_fbx_id(ufbxi_context *uc, uint64_t fbx_id)
  9976. {
  9977. uint32_t hash = ufbxi_hash64(fbx_id);
  9978. return ufbxi_map_find(&uc->fbx_id_map, ufbxi_fbx_id_entry, hash, &fbx_id);
  9979. }
  9980. static ufbxi_forceinline bool ufbxi_fbx_id_exists(ufbxi_context *uc, uint64_t fbx_id)
  9981. {
  9982. return ufbxi_find_fbx_id(uc, fbx_id) != NULL;
  9983. }
  9984. ufbxi_nodiscard ufbxi_noinline static int ufbxi_insert_fbx_attr(ufbxi_context *uc, uint64_t fbx_id, uint64_t attrib_fbx_id)
  9985. {
  9986. uint32_t hash = ufbxi_hash64(fbx_id);
  9987. ufbxi_fbx_attr_entry *entry = ufbxi_map_find(&uc->fbx_attr_map, ufbxi_fbx_attr_entry, hash, &fbx_id);
  9988. // TODO: Strict / warn about duplicate objects
  9989. if (!entry) {
  9990. entry = ufbxi_map_insert(&uc->fbx_attr_map, ufbxi_fbx_attr_entry, hash, &fbx_id);
  9991. ufbxi_check(entry);
  9992. entry->node_fbx_id = fbx_id;
  9993. entry->attr_fbx_id = attrib_fbx_id;
  9994. }
  9995. return 1;
  9996. }
  9997. ufbxi_nodiscard ufbxi_noinline static ufbx_element *ufbxi_push_element_size(ufbxi_context *uc, ufbxi_element_info *info, size_t size, ufbx_element_type type)
  9998. {
  9999. size_t aligned_size = (size + 7u) & ~0x7u;
  10000. uint32_t typed_id = (uint32_t)uc->tmp_typed_element_offsets[type].num_items;
  10001. uint32_t element_id = uc->num_elements++;
  10002. ufbxi_check_return(ufbxi_push_copy_fast(&uc->tmp_typed_element_offsets[type], size_t, 1, &uc->tmp_element_byte_offset), NULL);
  10003. ufbxi_check_return(ufbxi_push_copy_fast(&uc->tmp_element_offsets, size_t, 1, &uc->tmp_element_byte_offset), NULL);
  10004. ufbxi_check_return(ufbxi_push_copy_fast(&uc->tmp_element_fbx_ids, uint64_t, 1, &info->fbx_id), NULL);
  10005. uc->tmp_element_byte_offset += aligned_size;
  10006. ufbx_element *elem = (ufbx_element*)ufbxi_push_zero(&uc->tmp_elements, uint64_t, aligned_size/8);
  10007. ufbxi_check_return(elem, NULL);
  10008. elem->type = type;
  10009. elem->element_id = element_id;
  10010. elem->typed_id = typed_id;
  10011. elem->name = info->name;
  10012. elem->props = info->props;
  10013. elem->dom_node = info->dom_node;
  10014. if (uc->p_element_id) {
  10015. *uc->p_element_id = element_id;
  10016. }
  10017. ufbxi_check_return(ufbxi_push_copy_fast(&uc->tmp_element_ptrs, ufbx_element*, 1, &elem), NULL);
  10018. ufbxi_check_return(ufbxi_insert_fbx_id(uc, info->fbx_id, element_id), NULL);
  10019. return elem;
  10020. }
  10021. ufbxi_nodiscard ufbxi_noinline static ufbx_element *ufbxi_push_synthetic_element_size(ufbxi_context *uc, uint64_t *p_fbx_id, ufbxi_node *node, const char *name, size_t size, ufbx_element_type type)
  10022. {
  10023. size_t aligned_size = (size + 7u) & ~0x7u;
  10024. uint32_t typed_id = (uint32_t)uc->tmp_typed_element_offsets[type].num_items;
  10025. uint32_t element_id = uc->num_elements++;
  10026. ufbxi_check_return(ufbxi_push_copy_fast(&uc->tmp_typed_element_offsets[type], size_t, 1, &uc->tmp_element_byte_offset), NULL);
  10027. ufbxi_check_return(ufbxi_push_copy_fast(&uc->tmp_element_offsets, size_t, 1, &uc->tmp_element_byte_offset), NULL);
  10028. uc->tmp_element_byte_offset += aligned_size;
  10029. ufbx_element *elem = (ufbx_element*)ufbxi_push_zero(&uc->tmp_elements, uint64_t, aligned_size/8);
  10030. ufbxi_check_return(elem, NULL);
  10031. elem->type = type;
  10032. elem->element_id = element_id;
  10033. elem->typed_id = typed_id;
  10034. elem->dom_node = ufbxi_get_dom_node(uc, node);
  10035. if (name) {
  10036. elem->name.data = name;
  10037. elem->name.length = strlen(name);
  10038. }
  10039. ufbxi_check_return(ufbxi_push_copy_fast(&uc->tmp_element_ptrs, ufbx_element*, 1, &elem), NULL);
  10040. uint64_t fbx_id = ufbxi_synthetic_id_from_pointer(elem);
  10041. *p_fbx_id = fbx_id;
  10042. ufbxi_check_return(ufbxi_push_copy_fast(&uc->tmp_element_fbx_ids, uint64_t, 1, &fbx_id), NULL);
  10043. ufbxi_check_return(ufbxi_insert_fbx_id(uc, fbx_id, element_id), NULL);
  10044. return elem;
  10045. }
  10046. #define ufbxi_push_element(uc, info, type_name, type_enum) ufbxi_maybe_null((type_name*)ufbxi_push_element_size((uc), (info), sizeof(type_name), (type_enum)))
  10047. #define ufbxi_push_synthetic_element(uc, p_fbx_id, node, name, type_name, type_enum) ufbxi_maybe_null((type_name*)ufbxi_push_synthetic_element_size((uc), (p_fbx_id), (node), (name), sizeof(type_name), (type_enum)))
  10048. ufbxi_nodiscard ufbxi_noinline static int ufbxi_connect_oo(ufbxi_context *uc, uint64_t src, uint64_t dst)
  10049. {
  10050. ufbxi_tmp_connection *conn = ufbxi_push(&uc->tmp_connections, ufbxi_tmp_connection, 1);
  10051. ufbxi_check(conn);
  10052. conn->src = src;
  10053. conn->dst = dst;
  10054. conn->src_prop = conn->dst_prop = ufbx_empty_string;
  10055. return 1;
  10056. }
  10057. ufbxi_nodiscard ufbxi_noinline static int ufbxi_connect_op(ufbxi_context *uc, uint64_t src, uint64_t dst, ufbx_string prop)
  10058. {
  10059. ufbxi_tmp_connection *conn = ufbxi_push(&uc->tmp_connections, ufbxi_tmp_connection, 1);
  10060. ufbxi_check(conn);
  10061. conn->src = src;
  10062. conn->dst = dst;
  10063. conn->src_prop = ufbx_empty_string;
  10064. conn->dst_prop = prop;
  10065. return 1;
  10066. }
  10067. ufbxi_nodiscard ufbxi_noinline static int ufbxi_connect_pp(ufbxi_context *uc, uint64_t src, uint64_t dst, ufbx_string src_prop, ufbx_string dst_prop)
  10068. {
  10069. ufbxi_tmp_connection *conn = ufbxi_push(&uc->tmp_connections, ufbxi_tmp_connection, 1);
  10070. ufbxi_check(conn);
  10071. conn->src = src;
  10072. conn->dst = dst;
  10073. conn->src_prop = src_prop;
  10074. conn->dst_prop = dst_prop;
  10075. return 1;
  10076. }
  10077. ufbxi_noinline static void ufbxi_init_synthetic_int_prop(ufbx_prop *dst, const char *name, int64_t value, ufbx_prop_type type)
  10078. {
  10079. dst->type = type;
  10080. dst->name.data = name;
  10081. dst->name.length = strlen(name);
  10082. dst->value_real = (ufbx_real)value;
  10083. dst->flags = (ufbx_prop_flags)(UFBX_PROP_FLAG_SYNTHETIC|UFBX_PROP_FLAG_VALUE_REAL|UFBX_PROP_FLAG_VALUE_INT);
  10084. dst->value_int = value;
  10085. dst->value_str.data = ufbxi_empty_char;
  10086. ufbxi_dev_assert(dst->name.length >= 4);
  10087. dst->_internal_key = ufbxi_get_name_key(name, 4);
  10088. }
  10089. ufbxi_noinline static void ufbxi_init_synthetic_real_prop(ufbx_prop *dst, const char *name, ufbx_real value, ufbx_prop_type type)
  10090. {
  10091. dst->type = type;
  10092. dst->name.data = name;
  10093. dst->name.length = strlen(name);
  10094. dst->value_real = value;
  10095. dst->flags = (ufbx_prop_flags)(UFBX_PROP_FLAG_SYNTHETIC|UFBX_PROP_FLAG_VALUE_REAL);
  10096. dst->value_int = (int64_t)value;
  10097. dst->value_str.data = ufbxi_empty_char;
  10098. ufbxi_dev_assert(dst->name.length >= 4);
  10099. dst->_internal_key = ufbxi_get_name_key(name, 4);
  10100. }
  10101. ufbxi_noinline static void ufbxi_init_synthetic_vec3_prop(ufbx_prop *dst, const char *name, const ufbx_vec3 *value, ufbx_prop_type type)
  10102. {
  10103. dst->type = type;
  10104. dst->name.data = name;
  10105. dst->name.length = strlen(name);
  10106. dst->value_vec3 = *value;
  10107. dst->flags = (ufbx_prop_flags)(UFBX_PROP_FLAG_SYNTHETIC|UFBX_PROP_FLAG_VALUE_VEC3);
  10108. dst->value_int = ufbxi_f64_to_i64(dst->value_real);
  10109. dst->value_str.data = ufbxi_empty_char;
  10110. ufbxi_dev_assert(dst->name.length >= 4);
  10111. dst->_internal_key = ufbxi_get_name_key(name, 4);
  10112. }
  10113. ufbxi_noinline static void ufbxi_set_own_prop_vec3_uniform(ufbx_props *props, const char *name, ufbx_real value)
  10114. {
  10115. ufbx_props local_props = *props;
  10116. local_props.defaults = NULL;
  10117. ufbx_prop *prop = ufbx_find_prop(&local_props, name);
  10118. if (prop) {
  10119. prop->value_vec4.x = value;
  10120. prop->value_vec4.y = value;
  10121. prop->value_vec4.z = value;
  10122. prop->value_vec4.w = 0.0f;
  10123. prop->value_int = (int64_t)value;
  10124. }
  10125. }
  10126. typedef struct {
  10127. uint32_t geometry_helper_id;
  10128. uint32_t scale_helper_id;
  10129. } ufbxi_node_extra;
  10130. ufbxi_nodiscard ufbxi_noinline static int ufbxi_setup_geometry_transform_helper(ufbxi_context *uc, ufbx_node *node, uint64_t node_fbx_id)
  10131. {
  10132. ufbx_vec3 geo_translation = ufbxi_find_vec3(&node->props, ufbxi_GeometricTranslation, 0.0f, 0.0f, 0.0f);
  10133. ufbx_vec3 geo_rotation = ufbxi_find_vec3(&node->props, ufbxi_GeometricRotation, 0.0f, 0.0f, 0.0f);
  10134. ufbx_vec3 geo_scaling = ufbxi_find_vec3(&node->props, ufbxi_GeometricScaling, 1.0f, 1.0f, 1.0f);
  10135. if (!ufbxi_is_vec3_zero(geo_translation) || !ufbxi_is_vec3_zero(geo_rotation) || !ufbxi_is_vec3_one(geo_scaling)) {
  10136. uint64_t geo_fbx_id;
  10137. ufbx_node *geo_node = ufbxi_push_synthetic_element(uc, &geo_fbx_id, NULL, uc->opts.geometry_transform_helper_name.data, ufbx_node, UFBX_ELEMENT_NODE);
  10138. ufbxi_check(geo_node);
  10139. ufbxi_check(ufbxi_push_copy(&uc->tmp_node_ids, uint32_t, 1, &geo_node->element.element_id));
  10140. geo_node->element.dom_node = node->element.dom_node;
  10141. ufbx_prop *props = ufbxi_push_zero(&uc->result, ufbx_prop, 3);
  10142. ufbxi_check(props);
  10143. ufbxi_init_synthetic_vec3_prop(&props[0], ufbxi_Lcl_Rotation, &geo_rotation, UFBX_PROP_ROTATION);
  10144. ufbxi_init_synthetic_vec3_prop(&props[1], ufbxi_Lcl_Scaling, &geo_scaling, UFBX_PROP_SCALING);
  10145. ufbxi_init_synthetic_vec3_prop(&props[2], ufbxi_Lcl_Translation, &geo_translation, UFBX_PROP_TRANSLATION);
  10146. geo_node->props.props.data = props;
  10147. geo_node->props.props.count = 3;
  10148. node->has_geometry_transform = true;
  10149. geo_node->is_geometry_transform_helper = true;
  10150. ufbxi_check(ufbxi_connect_oo(uc, geo_fbx_id, node_fbx_id));
  10151. uc->has_geometry_transform_nodes = true;
  10152. ufbxi_node_extra *extra = ufbxi_push_element_extra(uc, node->element_id, ufbxi_node_extra);
  10153. ufbxi_check(extra);
  10154. extra->geometry_helper_id = geo_node->element_id;
  10155. }
  10156. return 1;
  10157. }
  10158. typedef struct {
  10159. const char *name;
  10160. ufbx_vec3 default_value;
  10161. } ufbxi_scale_helper_prop;
  10162. static const ufbxi_scale_helper_prop ufbxi_scale_helper_props[] = {
  10163. { ufbxi_GeometricRotation, { 0.0f, 0.0f, 0.0f } },
  10164. { ufbxi_GeometricScaling, { 1.0f, 1.0f, 1.0f } },
  10165. { ufbxi_GeometricTranslation, { 0.0f, 0.0f, 0.0f } },
  10166. { ufbxi_Lcl_Scaling, { 1.0f, 1.0f, 1.0f } },
  10167. };
  10168. ufbxi_nodiscard ufbxi_noinline static int ufbxi_setup_scale_helper(ufbxi_context *uc, ufbx_node *node, uint64_t node_fbx_id)
  10169. {
  10170. uint64_t scale_fbx_id;
  10171. ufbx_node *scale_node = ufbxi_push_synthetic_element(uc, &scale_fbx_id, NULL, uc->opts.scale_helper_name.data, ufbx_node, UFBX_ELEMENT_NODE);
  10172. ufbxi_check(scale_node);
  10173. ufbxi_check(ufbxi_push_copy(&uc->tmp_node_ids, uint32_t, 1, &scale_node->element.element_id));
  10174. scale_node->element.dom_node = node->element.dom_node;
  10175. node->scale_helper = scale_node;
  10176. scale_node->is_scale_helper = true;
  10177. ufbxi_check(ufbxi_connect_oo(uc, scale_fbx_id, node_fbx_id));
  10178. uc->has_scale_helper_nodes = true;
  10179. ufbxi_node_extra *extra = ufbxi_push_element_extra(uc, node->element.element_id, ufbxi_node_extra);
  10180. ufbxi_check(extra);
  10181. extra->scale_helper_id = scale_node->element_id;
  10182. size_t max_props = ufbxi_arraycount(ufbxi_scale_helper_props);
  10183. ufbx_prop *helper_props = ufbxi_push(&uc->result, ufbx_prop, max_props);
  10184. ufbxi_check(helper_props);
  10185. size_t num_props = 0;
  10186. ufbx_props props_copy = node->props;
  10187. props_copy.defaults = NULL;
  10188. for (size_t i = 0; i < max_props; i++) {
  10189. const ufbxi_scale_helper_prop *hp = &ufbxi_scale_helper_props[i];
  10190. ufbx_prop *src_prop = ufbxi_find_prop(&props_copy, hp->name);
  10191. if (!src_prop) continue;
  10192. helper_props[num_props++] = *src_prop;
  10193. src_prop->value_vec3 = hp->default_value;
  10194. src_prop->value_int = (int64_t)src_prop->value_vec3.x;
  10195. }
  10196. scale_node->props.props.data = helper_props;
  10197. scale_node->props.props.count = num_props;
  10198. return 1;
  10199. }
  10200. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_model(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  10201. {
  10202. (void)node;
  10203. ufbx_node *elem_node = ufbxi_push_element(uc, info, ufbx_node, UFBX_ELEMENT_NODE);
  10204. ufbxi_check(elem_node);
  10205. ufbxi_check(ufbxi_push_copy(&uc->tmp_node_ids, uint32_t, 1, &elem_node->element.element_id));
  10206. int64_t inherit_type = ufbxi_find_int(&elem_node->props, ufbxi_InheritType, -1);
  10207. switch (inherit_type) {
  10208. case 0: // RrSs
  10209. elem_node->original_inherit_mode = UFBX_INHERIT_MODE_COMPONENTWISE_SCALE;
  10210. break;
  10211. case 2: // Rrs
  10212. elem_node->original_inherit_mode = UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE;
  10213. break;
  10214. default: break;
  10215. }
  10216. if (uc->opts.inherit_mode_handling == UFBX_INHERIT_MODE_HANDLING_PRESERVE) {
  10217. elem_node->inherit_mode = elem_node->original_inherit_mode;
  10218. } else if (uc->opts.inherit_mode_handling == UFBX_INHERIT_MODE_HANDLING_IGNORE) {
  10219. elem_node->original_inherit_mode = UFBX_INHERIT_MODE_NORMAL;
  10220. elem_node->inherit_mode = UFBX_INHERIT_MODE_NORMAL;
  10221. }
  10222. return 1;
  10223. }
  10224. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_element(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info, size_t size, ufbx_element_type type)
  10225. {
  10226. (void)node;
  10227. ufbx_element *elem = ufbxi_push_element_size(uc, info, size, type);
  10228. ufbxi_check(elem);
  10229. return 1;
  10230. }
  10231. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_unknown(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *element, ufbx_string type, ufbx_string sub_type, const char *node_name)
  10232. {
  10233. (void)node;
  10234. ufbx_unknown *unknown = ufbxi_push_element(uc, element, ufbx_unknown, UFBX_ELEMENT_UNKNOWN);
  10235. ufbxi_check(unknown);
  10236. unknown->type = type;
  10237. unknown->sub_type = sub_type;
  10238. unknown->super_type.data = node_name;
  10239. unknown->super_type.length = strlen(node_name);
  10240. // `type`, `sub_type` and `node_name` are raw strings so they may need to be sanitized.
  10241. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &unknown->type, false));
  10242. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &unknown->sub_type, false));
  10243. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &unknown->super_type, false));
  10244. return 1;
  10245. }
  10246. typedef struct {
  10247. ufbx_vertex_vec3 elem;
  10248. uint32_t index;
  10249. } ufbxi_tangent_layer;
  10250. static ufbx_real ufbxi_zero_element[8] = { 0 };
  10251. // Sentinel pointers used for zero/sequential index buffers
  10252. static const uint32_t ufbxi_sentinel_index_zero[1] = { 100000000 };
  10253. static const uint32_t ufbxi_sentinel_index_consecutive[1] = { 123456789 };
  10254. ufbxi_noinline static int ufbxi_fix_index(ufbxi_context *uc, uint32_t *p_dst, uint32_t index, size_t one_past_max_val)
  10255. {
  10256. switch (uc->opts.index_error_handling) {
  10257. case UFBX_INDEX_ERROR_HANDLING_CLAMP:
  10258. ufbxi_check(one_past_max_val > 0);
  10259. ufbxi_check(one_past_max_val <= UINT32_MAX);
  10260. *p_dst = (uint32_t)one_past_max_val - 1;
  10261. ufbxi_check(ufbxi_warnf(UFBX_WARNING_INDEX_CLAMPED, "Clamped index"));
  10262. break;
  10263. case UFBX_INDEX_ERROR_HANDLING_NO_INDEX:
  10264. *p_dst = UFBX_NO_INDEX;
  10265. break;
  10266. case UFBX_INDEX_ERROR_HANDLING_ABORT_LOADING:
  10267. ufbxi_fmt_err_info(&uc->error, "%u (max %u)", index, one_past_max_val ? (one_past_max_val - 1) : 0);
  10268. ufbxi_fail_msg("UFBX_INDEX_ERROR_HANDLING_ABORT_LOADING", "Bad index");
  10269. case UFBX_INDEX_ERROR_HANDLING_UNSAFE_IGNORE:
  10270. *p_dst = index;
  10271. break;
  10272. default:
  10273. ufbxi_unreachable("Unhandled index_error_handling");
  10274. return 0;
  10275. }
  10276. return 1;
  10277. }
  10278. ufbxi_nodiscard ufbxi_noinline static int ufbxi_check_indices(ufbxi_context *uc, uint32_t **p_dst, uint32_t *indices, bool owns_indices, size_t num_indices, size_t num_indexers, size_t num_elems)
  10279. {
  10280. // If the indices are truncated extend them with `UFBX_NO_INDEX`, the following normalization pass
  10281. // will handle them the same way as other out-of-bounds indices.
  10282. if (num_indices < num_indexers) {
  10283. uint32_t *new_indices = ufbxi_push(&uc->result, uint32_t, num_indexers);
  10284. ufbxi_check(new_indices);
  10285. memcpy(new_indices, indices, sizeof(uint32_t) * num_indices);
  10286. for (size_t i = num_indices; i < num_indexers; i++) {
  10287. new_indices[i] = UFBX_NO_INDEX;
  10288. }
  10289. indices = new_indices;
  10290. num_indices = num_indexers;
  10291. owns_indices = true;
  10292. }
  10293. // Normalize out-of-bounds indices to `invalid_index`
  10294. for (size_t i = 0; i < num_indices; i++) {
  10295. uint32_t ix = indices[i];
  10296. if (ix >= num_elems) {
  10297. // If the indices refer to an external buffer we need to
  10298. // allocate a separate buffer for them
  10299. if (!owns_indices) {
  10300. indices = ufbxi_push_copy(&uc->result, uint32_t, num_indices, indices);
  10301. ufbxi_check(indices);
  10302. owns_indices = true;
  10303. }
  10304. ufbxi_check(ufbxi_fix_index(uc, &indices[i], ix, num_elems));
  10305. }
  10306. }
  10307. *p_dst = indices;
  10308. return 1;
  10309. }
  10310. ufbx_static_assert(vertex_real_size, sizeof(ufbx_vertex_real) == sizeof(ufbx_vertex_attrib));
  10311. ufbx_static_assert(vertex_vec2_size, sizeof(ufbx_vertex_vec2) == sizeof(ufbx_vertex_attrib));
  10312. ufbx_static_assert(vertex_vec3_size, sizeof(ufbx_vertex_vec3) == sizeof(ufbx_vertex_attrib));
  10313. ufbx_static_assert(vertex_vec4_size, sizeof(ufbx_vertex_vec4) == sizeof(ufbx_vertex_attrib));
  10314. ufbxi_nodiscard ufbxi_noinline static int ufbxi_warn_polygon_mapping(ufbxi_context *uc, const char *data_name, const char *mapping)
  10315. {
  10316. ufbxi_check(ufbxi_warnf(UFBX_WARNING_MISSING_POLYGON_MAPPING, "Ignoring geometry '%s' with bad mapping mode '%s'", data_name, mapping));
  10317. return 1;
  10318. }
  10319. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_vertex_element(ufbxi_context *uc, ufbx_mesh *mesh, ufbxi_node *node,
  10320. ufbx_vertex_attrib *attrib, const char *data_name, const char *index_name, const char *w_name, char data_type, size_t num_components)
  10321. {
  10322. ufbx_real **p_dst_data = (ufbx_real**)&attrib->values.data;
  10323. ufbxi_value_array *data = ufbxi_find_array(node, data_name, data_type);
  10324. ufbxi_value_array *indices = ufbxi_find_array(node, index_name, 'i');
  10325. if (!uc->opts.strict) {
  10326. if (!data) return 1;
  10327. }
  10328. ufbxi_check(data);
  10329. ufbxi_check(data->size % num_components == 0);
  10330. size_t num_elems = data->size / num_components;
  10331. // HACK: If there's no elements at all keep the attribute as NULL
  10332. // TODO: Strict mode for this?
  10333. if (num_elems == 0) {
  10334. return 1;
  10335. }
  10336. ufbxi_check(num_elems > 0 && num_elems < INT32_MAX);
  10337. attrib->exists = true;
  10338. attrib->indices.count = mesh->num_indices;
  10339. const char *mapping = "";
  10340. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_MappingInformationType, "C", (char**)&mapping));
  10341. attrib->values.count = num_elems ? num_elems : 1;
  10342. // Data array is always used as-is, if empty set the data to a global
  10343. // zero buffer so invalid zero index can point to some valid data.
  10344. // The zero data is offset by 4 elements to accommodate for invalid index (-1)
  10345. if (num_elems > 0) {
  10346. *p_dst_data = (ufbx_real*)data->data;
  10347. } else {
  10348. *p_dst_data = ufbxi_zero_element + 4;
  10349. }
  10350. // HACK: Some old exporters seem to use ByPolygon to mean ByPolygonVertex,
  10351. // it should be quite safe to remap this
  10352. if (mapping == ufbxi_ByPolygon) {
  10353. size_t num_indices = indices ? indices->size : num_elems;
  10354. if (num_indices == mesh->num_indices) {
  10355. mapping = ufbxi_ByPolygonVertex;
  10356. }
  10357. }
  10358. if (indices) {
  10359. size_t num_indices = indices->size;
  10360. uint32_t *index_data = (uint32_t*)indices->data;
  10361. if (mapping == ufbxi_ByPolygonVertex) {
  10362. // Indexed by polygon vertex: We can use the provided indices directly.
  10363. ufbxi_check(ufbxi_check_indices(uc, &attrib->indices.data, index_data, true, num_indices, mesh->num_indices, num_elems));
  10364. } else if (mapping == ufbxi_ByVertex || mapping == ufbxi_ByVertice) {
  10365. // Indexed by vertex: Follow through the position index mapping to get the final indices.
  10366. uint32_t *new_index_data = ufbxi_push(&uc->result, uint32_t, mesh->num_indices);
  10367. ufbxi_check(new_index_data);
  10368. uint32_t *vert_ix = mesh->vertex_indices.data;
  10369. for (size_t i = 0; i < mesh->num_indices; i++) {
  10370. uint32_t ix = vert_ix[i];
  10371. if (ix < num_indices) {
  10372. new_index_data[i] = index_data[ix];
  10373. } else {
  10374. ufbxi_check(ufbxi_fix_index(uc, &new_index_data[i], ix, num_elems));
  10375. }
  10376. }
  10377. ufbxi_check(ufbxi_check_indices(uc, &attrib->indices.data, new_index_data, true, mesh->num_indices, mesh->num_indices, num_elems));
  10378. attrib->unique_per_vertex = true;
  10379. } else if (mapping == ufbxi_ByPolygon) {
  10380. // Indexed by polygon: Generate new indices based on polygons
  10381. uint32_t *new_index_data = ufbxi_push(&uc->result, uint32_t, mesh->num_indices);
  10382. ufbxi_check(new_index_data);
  10383. size_t num_faces = mesh->num_faces;
  10384. for (size_t face_ix = 0; face_ix < num_faces; face_ix++) {
  10385. ufbx_face face = mesh->faces.data[face_ix];
  10386. uint32_t index = UFBX_NO_INDEX;
  10387. if (face_ix < num_indices) {
  10388. index = index_data[face_ix];
  10389. }
  10390. if (index >= num_elems) {
  10391. ufbxi_check(ufbxi_fix_index(uc, &index, index, num_elems));
  10392. }
  10393. for (size_t i = 0; i < face.num_indices; i++) {
  10394. new_index_data[face.index_begin + i] = index;
  10395. }
  10396. }
  10397. attrib->indices.data = new_index_data;
  10398. } else if (mapping == ufbxi_AllSame) {
  10399. // Indexed by all same: ??? This could be possibly used for making
  10400. // holes with invalid indices, but that seems really fringe.
  10401. // Just use the shared zero index buffer for this.
  10402. uc->max_zero_indices = ufbxi_max_sz(uc->max_zero_indices, mesh->num_indices);
  10403. attrib->indices.data = (uint32_t*)ufbxi_sentinel_index_zero;
  10404. attrib->unique_per_vertex = true;
  10405. } else {
  10406. memset(attrib, 0, sizeof(ufbx_vertex_attrib));
  10407. ufbxi_check(ufbxi_warn_polygon_mapping(uc, data_name, mapping));
  10408. return 1;
  10409. }
  10410. } else {
  10411. if (mapping == ufbxi_ByPolygonVertex) {
  10412. // Direct by polygon index: Use shared consecutive array if there's enough
  10413. // elements, otherwise use a unique truncated consecutive index array.
  10414. if (num_elems >= mesh->num_indices) {
  10415. uc->max_consecutive_indices = ufbxi_max_sz(uc->max_consecutive_indices, mesh->num_indices);
  10416. attrib->indices.data = (uint32_t*)ufbxi_sentinel_index_consecutive;
  10417. } else {
  10418. uint32_t *index_data = ufbxi_push(&uc->result, uint32_t, mesh->num_indices);
  10419. ufbxi_check(index_data);
  10420. for (size_t i = 0; i < mesh->num_indices; i++) {
  10421. index_data[i] = (uint32_t)i;
  10422. }
  10423. ufbxi_check(ufbxi_check_indices(uc, &attrib->indices.data, index_data, true, mesh->num_indices, mesh->num_indices, num_elems));
  10424. }
  10425. } else if (mapping == ufbxi_ByVertex || mapping == ufbxi_ByVertice) {
  10426. // Direct by vertex: We can re-use the position indices..
  10427. ufbxi_check(ufbxi_check_indices(uc, &attrib->indices.data, mesh->vertex_position.indices.data, false, mesh->num_indices, mesh->num_indices, num_elems));
  10428. attrib->unique_per_vertex = true;
  10429. } else if (mapping == ufbxi_ByPolygon) {
  10430. // Direct by polygon: Generate new indices based on polygons
  10431. uint32_t *new_index_data = ufbxi_push(&uc->result, uint32_t, mesh->num_indices);
  10432. ufbxi_check(new_index_data);
  10433. uint32_t num_faces = (uint32_t)mesh->num_faces;
  10434. for (uint32_t face_ix = 0; face_ix < num_faces; face_ix++) {
  10435. ufbx_face face = mesh->faces.data[face_ix];
  10436. for (size_t i = 0; i < face.num_indices; i++) {
  10437. new_index_data[face.index_begin + i] = face_ix;
  10438. }
  10439. }
  10440. ufbxi_check(ufbxi_check_indices(uc, &attrib->indices.data, new_index_data, true, mesh->num_indices, mesh->num_indices, num_elems));
  10441. } else if (mapping == ufbxi_AllSame) {
  10442. // Direct by all same: This cannot fail as the index list is just zero.
  10443. uc->max_zero_indices = ufbxi_max_sz(uc->max_zero_indices, mesh->num_indices);
  10444. attrib->indices.data = (uint32_t*)ufbxi_sentinel_index_zero;
  10445. attrib->unique_per_vertex = true;
  10446. } else {
  10447. memset(attrib, 0, sizeof(ufbx_vertex_attrib));
  10448. ufbxi_check(ufbxi_warn_polygon_mapping(uc, data_name, mapping));
  10449. return 1;
  10450. }
  10451. }
  10452. if (uc->opts.retain_vertex_attrib_w && w_name) {
  10453. ufbxi_value_array *w_data = ufbxi_find_array(node, w_name, 'r');
  10454. if (w_data) {
  10455. if (w_data->size == num_elems) {
  10456. attrib->values_w.count = w_data->size;
  10457. attrib->values_w.data = (ufbx_real*)w_data->data;
  10458. } else {
  10459. ufbxi_check(ufbxi_warnf(UFBX_WARNING_BAD_VERTEX_W_ATTRIBUTE, "Bad W array size %s=%zu, %s=%zu",
  10460. w_name, w_data->size, data_name, num_elems));
  10461. }
  10462. }
  10463. }
  10464. return 1;
  10465. }
  10466. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_truncated_array(ufbxi_context *uc, void *p_data, size_t *p_count, ufbxi_node *node, const char *name, char fmt, size_t size)
  10467. {
  10468. ufbxi_value_array *arr = ufbxi_find_array(node, name, fmt);
  10469. if (!arr) {
  10470. ufbxi_check(ufbxi_warnf(UFBX_WARNING_MISSING_GEOMETRY_DATA, "Missing geometry data: %s", name));
  10471. return 1;
  10472. }
  10473. *p_count = size;
  10474. void *data = arr->data;
  10475. if (arr->size < size) {
  10476. ufbxi_check(ufbxi_warnf(UFBX_WARNING_TRUNCATED_ARRAY, "Truncated array: %s", name));
  10477. size_t elem_size = ufbxi_array_type_size(fmt);
  10478. void *new_data = ufbxi_push_size(&uc->result, elem_size, size);
  10479. ufbxi_check(new_data);
  10480. memcpy(new_data, data, arr->size * elem_size);
  10481. // Extend the array with the last element if possible
  10482. if (arr->size > 0) {
  10483. char *first_elem = (char*)data + (arr->size - 1) * elem_size;
  10484. for (size_t i = arr->size; i < size; i++) {
  10485. memcpy((char*)new_data + i * elem_size, first_elem, elem_size);
  10486. }
  10487. } else {
  10488. memset(new_data, 0, size * elem_size);
  10489. }
  10490. data = new_data;
  10491. }
  10492. *(void**)p_data = data;
  10493. return 1;
  10494. }
  10495. ufbxi_noinline static bool ufbxi_uv_set_less(void *user, const void *va, const void *vb)
  10496. {
  10497. (void)user;
  10498. const ufbx_uv_set *a = (const ufbx_uv_set *)va, *b = (const ufbx_uv_set *)vb;
  10499. return a->index < b->index;
  10500. }
  10501. ufbxi_noinline static bool ufbxi_color_set_less(void *user, const void *va, const void *vb)
  10502. {
  10503. (void)user;
  10504. const ufbx_color_set *a = (const ufbx_color_set *)va, *b = (const ufbx_color_set *)vb;
  10505. return a->index < b->index;
  10506. }
  10507. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_uv_sets(ufbxi_context *uc, ufbx_uv_set *sets, size_t count)
  10508. {
  10509. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_uv_set)));
  10510. ufbxi_stable_sort(sizeof(ufbx_uv_set), 32, sets, uc->tmp_arr, count, &ufbxi_uv_set_less, NULL);
  10511. return 1;
  10512. }
  10513. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_color_sets(ufbxi_context *uc, ufbx_color_set *sets, size_t count)
  10514. {
  10515. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_color_set)));
  10516. ufbxi_stable_sort(sizeof(ufbx_color_set), 32, sets, uc->tmp_arr, count, &ufbxi_color_set_less, NULL);
  10517. return 1;
  10518. }
  10519. typedef struct ufbxi_blend_offset {
  10520. uint32_t vertex;
  10521. ufbx_vec3 position_offset;
  10522. ufbx_vec3 normal_offset;
  10523. } ufbxi_blend_offset;
  10524. static ufbxi_noinline bool ufbxi_blend_offset_less(void *user, const void *va, const void *vb)
  10525. {
  10526. (void)user;
  10527. const ufbxi_blend_offset *a = (const ufbxi_blend_offset*)va, *b = (const ufbxi_blend_offset*)vb;
  10528. return a->vertex < b->vertex;
  10529. }
  10530. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_blend_offsets(ufbxi_context *uc, ufbxi_blend_offset *offsets, size_t count)
  10531. {
  10532. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbxi_blend_offset)));
  10533. ufbxi_stable_sort(sizeof(ufbxi_blend_offset), 16, offsets, uc->tmp_arr, count, &ufbxi_blend_offset_less, NULL);
  10534. return 1;
  10535. }
  10536. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_shape(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  10537. {
  10538. ufbxi_node *node_vertices = ufbxi_find_child(node, ufbxi_Vertices);
  10539. ufbxi_node *node_indices = ufbxi_find_child(node, ufbxi_Indexes);
  10540. ufbxi_node *node_normals = ufbxi_find_child(node, ufbxi_Normals);
  10541. if (!node_vertices || !node_indices) return 1;
  10542. ufbx_blend_shape *shape = ufbxi_push_element(uc, info, ufbx_blend_shape, UFBX_ELEMENT_BLEND_SHAPE);
  10543. ufbxi_check(shape);
  10544. if (uc->opts.ignore_geometry) return 1;
  10545. ufbxi_value_array *vertices = ufbxi_get_array(node_vertices, 'r');
  10546. ufbxi_value_array *indices = ufbxi_get_array(node_indices, 'i');
  10547. ufbxi_check(vertices && indices);
  10548. ufbxi_check(vertices->size % 3 == 0);
  10549. ufbxi_check(indices->size == vertices->size / 3);
  10550. size_t num_offsets = indices->size;
  10551. uint32_t *vertex_indices = (uint32_t*)indices->data;
  10552. shape->num_offsets = num_offsets;
  10553. shape->position_offsets.data = (ufbx_vec3*)vertices->data;
  10554. shape->offset_vertices.data = vertex_indices;
  10555. shape->position_offsets.count = num_offsets;
  10556. shape->offset_vertices.count = num_offsets;
  10557. if (node_normals) {
  10558. ufbxi_value_array *normals = ufbxi_get_array(node_normals, 'r');
  10559. ufbxi_check(normals && normals->size == vertices->size);
  10560. shape->normal_offsets.data = (ufbx_vec3*)normals->data;
  10561. shape->normal_offsets.count = num_offsets;
  10562. }
  10563. // Sort the blend shape vertices only if absolutely necessary
  10564. bool sorted = true;
  10565. for (size_t i = 1; i < num_offsets; i++) {
  10566. if (vertex_indices[i - 1] > vertex_indices[i]) {
  10567. sorted = false;
  10568. break;
  10569. }
  10570. }
  10571. if (!sorted) {
  10572. ufbxi_blend_offset *offsets = ufbxi_push(&uc->tmp_stack, ufbxi_blend_offset, num_offsets);
  10573. ufbxi_check(offsets);
  10574. for (size_t i = 0; i < num_offsets; i++) {
  10575. offsets[i].vertex = shape->offset_vertices.data[i];
  10576. offsets[i].position_offset = shape->position_offsets.data[i];
  10577. if (node_normals) offsets[i].normal_offset = shape->normal_offsets.data[i];
  10578. }
  10579. ufbxi_check(ufbxi_sort_blend_offsets(uc, offsets, num_offsets));
  10580. for (size_t i = 0; i < num_offsets; i++) {
  10581. shape->offset_vertices.data[i] = offsets[i].vertex;
  10582. shape->position_offsets.data[i] = offsets[i].position_offset;
  10583. if (node_normals) shape->normal_offsets.data[i] = offsets[i].normal_offset;
  10584. }
  10585. ufbxi_pop(&uc->tmp_stack, ufbxi_blend_offset, num_offsets, NULL);
  10586. }
  10587. return 1;
  10588. }
  10589. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_synthetic_blend_shapes(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  10590. {
  10591. ufbx_blend_deformer *deformer = NULL;
  10592. uint64_t deformer_fbx_id = 0;
  10593. ufbxi_for (ufbxi_node, n, node->children, node->num_children) {
  10594. if (n->name != ufbxi_Shape) continue;
  10595. ufbx_string name;
  10596. ufbxi_check(ufbxi_get_val1(n, "S", &name));
  10597. if (deformer == NULL) {
  10598. deformer = ufbxi_push_synthetic_element(uc, &deformer_fbx_id, n, name.data, ufbx_blend_deformer, UFBX_ELEMENT_BLEND_DEFORMER);
  10599. ufbxi_check(deformer);
  10600. ufbxi_check(ufbxi_connect_oo(uc, deformer_fbx_id, info->fbx_id));
  10601. }
  10602. uint64_t channel_fbx_id = 0;
  10603. ufbx_blend_channel *channel = ufbxi_push_synthetic_element(uc, &channel_fbx_id, n, name.data, ufbx_blend_channel, UFBX_ELEMENT_BLEND_CHANNEL);
  10604. ufbxi_check(channel);
  10605. ufbx_real_list weight_list = { NULL, 0 };
  10606. ufbxi_check(ufbxi_push_copy(&uc->tmp_full_weights, ufbx_real_list, 1, &weight_list));
  10607. size_t num_shape_props = 1;
  10608. ufbx_prop *shape_props = ufbxi_push_zero(&uc->result, ufbx_prop, num_shape_props);
  10609. ufbxi_check(shape_props);
  10610. shape_props[0].name.data = ufbxi_DeformPercent;
  10611. shape_props[0].name.length = sizeof(ufbxi_DeformPercent) - 1;
  10612. shape_props[0]._internal_key = ufbxi_get_name_key_c(ufbxi_DeformPercent);
  10613. shape_props[0].type = UFBX_PROP_NUMBER;
  10614. shape_props[0].value_real = (ufbx_real)0.0;
  10615. shape_props[0].value_str = ufbx_empty_string;
  10616. shape_props[0].value_blob = ufbx_empty_blob;
  10617. ufbx_prop *self_prop = ufbx_find_prop_len(&info->props, name.data, name.length);
  10618. if (self_prop && (self_prop->type == UFBX_PROP_NUMBER || self_prop->type == UFBX_PROP_INTEGER)) {
  10619. shape_props[0].value_real = self_prop->value_real;
  10620. ufbxi_check(ufbxi_connect_pp(uc, info->fbx_id, channel_fbx_id, name, shape_props[0].name));
  10621. } else if (uc->version < 6000) {
  10622. ufbxi_check(ufbxi_connect_pp(uc, info->fbx_id, channel_fbx_id, name, shape_props[0].name));
  10623. }
  10624. channel->name = name;
  10625. channel->props.props.data = shape_props;
  10626. channel->props.props.count = num_shape_props;
  10627. ufbxi_element_info shape_info = { 0 };
  10628. ufbxi_check(ufbxi_push_synthetic_id(uc, &shape_info.fbx_id));
  10629. shape_info.name = name;
  10630. shape_info.dom_node = ufbxi_get_dom_node(uc, n);
  10631. ufbxi_check(ufbxi_read_shape(uc, n, &shape_info));
  10632. ufbxi_check(ufbxi_connect_oo(uc, channel_fbx_id, deformer_fbx_id));
  10633. ufbxi_check(ufbxi_connect_oo(uc, shape_info.fbx_id, channel_fbx_id));
  10634. }
  10635. return 1;
  10636. }
  10637. ufbxi_nodiscard ufbxi_noinline static int ufbxi_process_indices(ufbxi_context *uc, ufbx_mesh *mesh, uint32_t *index_data)
  10638. {
  10639. // Count the number of faces and allocate the index list
  10640. // Indices less than zero (~actual_index) ends a polygon
  10641. size_t num_total_faces = 0;
  10642. ufbxi_for (uint32_t, p_ix, index_data, mesh->num_indices) {
  10643. num_total_faces += ((int32_t)*p_ix < 0) ? 1u : 0u;
  10644. }
  10645. mesh->faces.data = ufbxi_push(&uc->result, ufbx_face, num_total_faces);
  10646. ufbxi_check(mesh->faces.data);
  10647. size_t num_triangles = 0;
  10648. size_t max_face_triangles = 0;
  10649. size_t num_bad_faces[3] = { 0 };
  10650. ufbx_face *dst_face = mesh->faces.data;
  10651. uint32_t *p_face_begin = index_data;
  10652. ufbxi_for (uint32_t, p_ix, index_data, mesh->num_indices) {
  10653. uint32_t ix = *p_ix;
  10654. // Un-negate final indices of polygons
  10655. if ((int32_t)ix < 0) {
  10656. ix = ~ix;
  10657. *p_ix = ix;
  10658. uint32_t num_indices = (uint32_t)((p_ix - p_face_begin) + 1);
  10659. dst_face->index_begin = (uint32_t)(p_face_begin - index_data);
  10660. dst_face->num_indices = num_indices;
  10661. if (num_indices >= 3) {
  10662. num_triangles += num_indices - 2;
  10663. max_face_triangles = ufbxi_max_sz(max_face_triangles, num_indices - 2);
  10664. } else {
  10665. num_bad_faces[num_indices]++;
  10666. }
  10667. dst_face++;
  10668. p_face_begin = p_ix + 1;
  10669. }
  10670. ufbxi_check((size_t)ix < mesh->num_vertices);
  10671. }
  10672. mesh->vertex_position.indices.data = index_data;
  10673. mesh->num_faces = ufbxi_to_size(dst_face - mesh->faces.data);
  10674. mesh->faces.count = mesh->num_faces;
  10675. mesh->num_triangles = num_triangles;
  10676. mesh->max_face_triangles = max_face_triangles;
  10677. mesh->num_empty_faces = num_bad_faces[0];
  10678. mesh->num_point_faces = num_bad_faces[1];
  10679. mesh->num_line_faces = num_bad_faces[2];
  10680. mesh->vertex_first_index.count = mesh->num_vertices;
  10681. mesh->vertex_first_index.data = ufbxi_push(&uc->result, uint32_t, mesh->num_vertices);
  10682. ufbxi_check(mesh->vertex_first_index.data);
  10683. ufbxi_for_list(uint32_t, p_vx_ix, mesh->vertex_first_index) {
  10684. *p_vx_ix = UFBX_NO_INDEX;
  10685. }
  10686. {
  10687. size_t num_indices = mesh->num_indices;
  10688. size_t num_vertices = mesh->num_vertices;
  10689. uint32_t *vertex_indices = mesh->vertex_indices.data;
  10690. uint32_t *vertex_first_index = mesh->vertex_first_index.data;
  10691. for (size_t ix = 0; ix < num_indices; ix++) {
  10692. uint32_t vx = vertex_indices[ix];
  10693. if (vx < num_vertices) {
  10694. if (vertex_first_index[vx] == UFBX_NO_INDEX) {
  10695. vertex_first_index[vx] = (uint32_t)ix;
  10696. }
  10697. } else {
  10698. ufbxi_check(ufbxi_fix_index(uc, &vertex_indices[ix], vx, mesh->num_vertices));
  10699. }
  10700. }
  10701. }
  10702. // HACK(consecutive-faces): Prepare for finalize to re-use a consecutive/zero
  10703. // index buffer for face materials..
  10704. uc->max_zero_indices = ufbxi_max_sz(uc->max_zero_indices, mesh->num_faces);
  10705. uc->max_consecutive_indices = ufbxi_max_sz(uc->max_consecutive_indices, mesh->num_faces);
  10706. return 1;
  10707. }
  10708. ufbxi_noinline static void ufbxi_patch_mesh_reals(ufbx_mesh *mesh)
  10709. {
  10710. mesh->vertex_position.value_reals = 3;
  10711. mesh->vertex_normal.value_reals = 3;
  10712. mesh->vertex_uv.value_reals = 2;
  10713. mesh->vertex_tangent.value_reals = 3;
  10714. mesh->vertex_bitangent.value_reals = 3;
  10715. mesh->vertex_color.value_reals = 4;
  10716. mesh->vertex_crease.value_reals = 1;
  10717. mesh->skinned_position.value_reals = 3;
  10718. mesh->skinned_normal.value_reals = 3;
  10719. ufbxi_nounroll ufbxi_for_list(ufbx_uv_set, set, mesh->uv_sets) {
  10720. set->vertex_uv.value_reals = 2;
  10721. set->vertex_tangent.value_reals = 3;
  10722. set->vertex_bitangent.value_reals = 3;
  10723. }
  10724. ufbxi_nounroll ufbxi_for_list(ufbx_color_set, set, mesh->color_sets) {
  10725. set->vertex_color.value_reals = 4;
  10726. }
  10727. }
  10728. typedef struct {
  10729. uint32_t id, index;
  10730. } ufbxi_id_group;
  10731. static bool ufbxi_less_int32(void *user, const void *va, const void *vb)
  10732. {
  10733. (void)user;
  10734. const int32_t a = *(const int32_t*)va, b = *(const int32_t*)vb;
  10735. return a < b;
  10736. }
  10737. ufbx_static_assert(mesh_mat_point_faces, offsetof(ufbx_mesh_part, num_point_faces) - offsetof(ufbx_mesh_part, num_empty_faces) == 1 * sizeof(size_t));
  10738. ufbx_static_assert(mesh_mat_line_faces, offsetof(ufbx_mesh_part, num_line_faces) - offsetof(ufbx_mesh_part, num_empty_faces) == 2 * sizeof(size_t));
  10739. static ufbxi_forceinline void ufbxi_mesh_part_add_face(ufbx_mesh_part *part, uint32_t num_indices)
  10740. {
  10741. part->num_faces++;
  10742. if (num_indices >= 3) {
  10743. part->num_triangles += num_indices - 2;
  10744. } else {
  10745. // `num_empty/point/line_faces` are consecutive, see static asserts above.
  10746. // cppcheck-suppress objectIndex
  10747. (&part->num_empty_faces)[num_indices]++;
  10748. }
  10749. }
  10750. ufbxi_nodiscard static ufbxi_noinline int ufbxi_assign_face_groups(ufbxi_buf *buf, ufbx_error *error, ufbx_mesh *mesh, size_t *p_consecutive_indices, bool retain_parts)
  10751. {
  10752. size_t num_faces = mesh->num_faces;
  10753. ufbxi_check_err(error, num_faces > 0);
  10754. ufbxi_check_err(error, num_faces < UINT32_MAX);
  10755. ufbxi_check_err(error, mesh->face_group.count == num_faces);
  10756. uint32_t *ids = ufbxi_push(buf, uint32_t, num_faces);
  10757. ufbxi_check_err(error, ids);
  10758. uint32_t num_ids = 0;
  10759. ufbxi_id_group seen_ids[1 << UFBXI_FACE_GROUP_HASH_BITS];
  10760. memset(seen_ids, 0, sizeof(seen_ids));
  10761. uint32_t seed = 2654435769u;
  10762. uint32_t rehash_threshold = 256;
  10763. // Loosely deduplicate group IDs
  10764. ufbxi_for_list(uint32_t, p_id, mesh->face_group) {
  10765. uint32_t id = *p_id;
  10766. uint32_t id_hash = (id * seed) >> (32u - UFBXI_FACE_GROUP_HASH_BITS);
  10767. if (seen_ids[id_hash].id != id || seen_ids[id_hash].index == 0) {
  10768. seen_ids[id_hash].id = id;
  10769. if (++seen_ids[id_hash].index > rehash_threshold) {
  10770. seed *= seed;
  10771. rehash_threshold *= 2;
  10772. }
  10773. ids[num_ids++] = id;
  10774. }
  10775. }
  10776. // Sort and deduplicate remaining IDs
  10777. ufbxi_unstable_sort(ids, num_ids, sizeof(uint32_t), &ufbxi_less_int32, NULL);
  10778. size_t num_groups = 0;
  10779. for (size_t i = 0; i < num_ids; ) {
  10780. uint32_t id = ids[i];
  10781. ids[num_groups++] = id;
  10782. do { i++; } while (i < num_ids && ids[i] == id);
  10783. }
  10784. // Allocate group info structs
  10785. ufbx_face_group *groups = ufbxi_push_zero(buf, ufbx_face_group, num_groups);
  10786. ufbxi_check_err(error, groups);
  10787. for (size_t i = 0; i < num_groups; i++) {
  10788. groups[i].id = (int32_t)ids[i];
  10789. groups[i].name.data = ufbxi_empty_char;
  10790. }
  10791. mesh->face_groups.data = groups;
  10792. mesh->face_groups.count = num_groups;
  10793. ufbx_mesh_part *parts = NULL;
  10794. if (retain_parts) {
  10795. parts = ufbxi_push_zero(buf, ufbx_mesh_part, num_groups);
  10796. ufbxi_check_err(error, parts);
  10797. mesh->face_group_parts.data = parts;
  10798. mesh->face_group_parts.count = num_groups;
  10799. }
  10800. // Optimization: Use `consecutive_indices` for a single group
  10801. if (p_consecutive_indices && num_groups == 1) {
  10802. memset(mesh->face_group.data, 0, sizeof(uint32_t) * num_faces);
  10803. if (parts) {
  10804. parts[0].face_indices.data = (uint32_t*)ufbxi_sentinel_index_consecutive;
  10805. parts[0].face_indices.count = num_faces;
  10806. parts[0].num_empty_faces = mesh->num_empty_faces;
  10807. parts[0].num_point_faces = mesh->num_point_faces;
  10808. parts[0].num_line_faces = mesh->num_line_faces;
  10809. parts[0].num_faces = num_faces;
  10810. parts[0].num_triangles = mesh->num_triangles;
  10811. }
  10812. *p_consecutive_indices = ufbxi_max_sz(*p_consecutive_indices, num_faces);
  10813. return 1;
  10814. }
  10815. memset(seen_ids, 0, sizeof(seen_ids));
  10816. // Count faces and triangles per group and reassign IDs
  10817. const ufbx_face *p_face = mesh->faces.data;
  10818. ufbxi_for_list(uint32_t, p_id, mesh->face_group) {
  10819. uint32_t id = *p_id;
  10820. uint32_t id_hash = (id * seed) >> (32u - UFBXI_FACE_GROUP_HASH_BITS);
  10821. uint32_t num_indices = p_face->num_indices;
  10822. size_t index;
  10823. if (seen_ids[id_hash].id == id && seen_ids[id_hash].index > 0) {
  10824. index = seen_ids[id_hash].index - 1;
  10825. *p_id = (uint32_t)index;
  10826. } else {
  10827. int32_t signed_id = (int32_t)id;
  10828. index = SIZE_MAX;
  10829. ufbxi_macro_lower_bound_eq(ufbx_face_group, 8, &index, groups, 0, num_groups, ( a->id < signed_id ), ( a->id == signed_id ));
  10830. ufbx_assert(index < num_groups);
  10831. seen_ids[id_hash].id = id;
  10832. seen_ids[id_hash].index = (uint32_t)index + 1;
  10833. }
  10834. if (parts) {
  10835. ufbxi_mesh_part_add_face(&parts[index], num_indices);
  10836. }
  10837. *p_id = (uint32_t)index;
  10838. p_face++;
  10839. }
  10840. if (!parts) return 1;
  10841. // Subdivide `ids` for per-group `face_indices`
  10842. uint32_t *face_indices = ids;
  10843. uint32_t part_index = 0;
  10844. ufbxi_for(ufbx_mesh_part, part, parts, num_groups) {
  10845. part->index = part_index++;
  10846. part->face_indices.data = face_indices;
  10847. face_indices += part->num_faces;
  10848. }
  10849. ufbx_assert(face_indices == ids + num_faces);
  10850. // Collect per-group faces
  10851. uint32_t face_index = 0;
  10852. ufbxi_for_list(uint32_t, p_id, mesh->face_group) {
  10853. ufbx_mesh_part *part = &parts[*p_id];
  10854. part->face_indices.data[part->face_indices.count++] = face_index++;
  10855. }
  10856. return 1;
  10857. }
  10858. ufbxi_nodiscard static ufbxi_noinline int ufbxi_update_face_groups(ufbxi_buf *buf, ufbx_error *error, ufbx_mesh *mesh, bool need_copy)
  10859. {
  10860. size_t num_faces = mesh->faces.count;
  10861. size_t num_groups = mesh->face_group_parts.count;
  10862. if (num_groups == 0) return 1;
  10863. if (need_copy) {
  10864. mesh->face_group_parts.data = ufbxi_push_zero(buf, ufbx_mesh_part, num_groups);
  10865. ufbxi_check_err(error, mesh->face_group_parts.data);
  10866. }
  10867. uint32_t *face_indices = ufbxi_push(buf, uint32_t, num_faces);
  10868. ufbxi_check_err(error, face_indices);
  10869. ufbxi_nounroll for (size_t i = 0; i < num_faces; i++) {
  10870. ufbx_mesh_part *part = &mesh->face_group_parts.data[mesh->face_group.data[i]];
  10871. ufbxi_mesh_part_add_face(part, mesh->faces.data[i].num_indices);
  10872. }
  10873. uint32_t part_index = 0;
  10874. ufbxi_for_list(ufbx_mesh_part, part, mesh->face_group_parts) {
  10875. part->index = part_index++;
  10876. part->face_indices.data = face_indices;
  10877. part->face_indices.count = 0;
  10878. face_indices += part->num_faces;
  10879. }
  10880. ufbxi_nounroll for (uint32_t i = 0; i < num_faces; i++) {
  10881. ufbx_mesh_part *part = &mesh->face_group_parts.data[mesh->face_group.data[i]];
  10882. part->face_indices.data[part->face_indices.count++] = i;
  10883. }
  10884. return 1;
  10885. }
  10886. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_mesh(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  10887. {
  10888. ufbx_mesh *ufbxi_restrict mesh = ufbxi_push_element(uc, info, ufbx_mesh, UFBX_ELEMENT_MESH);
  10889. ufbxi_check(mesh);
  10890. // In up to version 7100 FBX files blend shapes are contained within the same geometry node
  10891. if (uc->version <= 7100) {
  10892. ufbxi_check(ufbxi_read_synthetic_blend_shapes(uc, node, info));
  10893. }
  10894. ufbxi_patch_mesh_reals(mesh);
  10895. // Sometimes there are empty meshes in FBX files?
  10896. // TODO: Should these be included in output? option? strict mode?
  10897. ufbxi_node *node_vertices = ufbxi_find_child(node, ufbxi_Vertices);
  10898. ufbxi_node *node_indices = ufbxi_find_child(node, ufbxi_PolygonVertexIndex);
  10899. if (!node_vertices) return 1;
  10900. if (uc->opts.ignore_geometry) return 1;
  10901. ufbxi_value_array *vertices = ufbxi_get_array(node_vertices, 'r');
  10902. ufbxi_value_array *indices = node_indices ? ufbxi_get_array(node_indices, 'i') : NULL;
  10903. ufbxi_value_array *edge_indices = ufbxi_find_array(node, ufbxi_Edges, 'i');
  10904. ufbxi_check(vertices);
  10905. ufbxi_check(!node_indices || indices); // If node_indices exists, it must be an array
  10906. ufbxi_check(vertices->size % 3 == 0);
  10907. mesh->num_vertices = vertices->size / 3;
  10908. mesh->num_indices = indices ? indices->size : 0;
  10909. uint32_t *index_data = indices ? (uint32_t*)indices->data : NULL;
  10910. // Duplicate `index_data` for modification if we retain DOM
  10911. if (uc->opts.retain_dom) {
  10912. index_data = ufbxi_push_copy(&uc->result, uint32_t, mesh->num_indices, index_data);
  10913. ufbxi_check(index_data);
  10914. }
  10915. mesh->vertices.data = (ufbx_vec3*)vertices->data;
  10916. mesh->vertices.count = mesh->num_vertices;
  10917. mesh->vertex_indices.data = index_data;
  10918. mesh->vertex_indices.count = mesh->num_indices;
  10919. mesh->vertex_position.exists = true;
  10920. mesh->vertex_position.values.data = (ufbx_vec3*)vertices->data;
  10921. mesh->vertex_position.values.count = mesh->num_vertices;
  10922. mesh->vertex_position.indices.data = index_data;
  10923. mesh->vertex_position.indices.count = mesh->num_indices;
  10924. mesh->vertex_position.unique_per_vertex = true;
  10925. // Check/make sure that the last index is negated (last of polygon)
  10926. if (mesh->num_indices > 0) {
  10927. if ((int32_t)index_data[mesh->num_indices - 1] >= 0) {
  10928. if (uc->opts.strict) ufbxi_fail("Non-negated last index");
  10929. index_data[mesh->num_indices - 1] = ~index_data[mesh->num_indices - 1];
  10930. }
  10931. }
  10932. // Read edges before un-negating the indices
  10933. if (edge_indices) {
  10934. size_t num_edges = edge_indices->size;
  10935. ufbx_edge *edges = ufbxi_push(&uc->result, ufbx_edge, num_edges);
  10936. ufbxi_check(edges);
  10937. size_t dst_ix = 0;
  10938. // Edges are represented using a single index into PolygonVertexIndex.
  10939. // The edge is between two consecutive vertices in the polygon.
  10940. uint32_t *edge_data = (uint32_t*)edge_indices->data;
  10941. for (size_t i = 0; i < num_edges; i++) {
  10942. uint32_t index_ix = edge_data[i];
  10943. if (index_ix >= mesh->num_indices) {
  10944. if (uc->opts.strict) ufbxi_fail("Edge index out of bounds");
  10945. continue;
  10946. }
  10947. edges[dst_ix].a = index_ix;
  10948. if ((int32_t)index_data[index_ix] < 0) {
  10949. // Previous index is the last one of this polygon, rewind to first index.
  10950. while (index_ix > 0 && (int32_t)index_data[index_ix - 1] >= 0) {
  10951. index_ix--;
  10952. }
  10953. } else {
  10954. // Connect to the next index in the same polygon
  10955. index_ix++;
  10956. }
  10957. ufbxi_check(index_ix < mesh->num_indices);
  10958. edges[dst_ix].b = index_ix;
  10959. dst_ix++;
  10960. }
  10961. mesh->edges.data = edges;
  10962. mesh->edges.count = dst_ix;
  10963. mesh->num_edges = mesh->edges.count;
  10964. }
  10965. ufbxi_check(ufbxi_process_indices(uc, mesh, index_data));
  10966. // Count the number of UV/color sets
  10967. size_t num_uv = 0, num_color = 0, num_bitangents = 0, num_tangents = 0;
  10968. ufbxi_for (ufbxi_node, n, node->children, node->num_children) {
  10969. if (n->name == ufbxi_LayerElementUV) num_uv++;
  10970. if (n->name == ufbxi_LayerElementColor) num_color++;
  10971. if (n->name == ufbxi_LayerElementBinormal) num_bitangents++;
  10972. if (n->name == ufbxi_LayerElementTangent) num_tangents++;
  10973. }
  10974. size_t num_textures = 0;
  10975. ufbxi_tangent_layer *bitangents = ufbxi_push_zero(&uc->tmp_stack, ufbxi_tangent_layer, num_bitangents);
  10976. ufbxi_tangent_layer *tangents = ufbxi_push_zero(&uc->tmp_stack, ufbxi_tangent_layer, num_tangents);
  10977. ufbxi_check(bitangents);
  10978. ufbxi_check(tangents);
  10979. mesh->uv_sets.data = ufbxi_push_zero(&uc->result, ufbx_uv_set, num_uv);
  10980. mesh->color_sets.data = ufbxi_push_zero(&uc->result, ufbx_color_set, num_color);
  10981. ufbxi_check(mesh->uv_sets.data);
  10982. ufbxi_check(mesh->color_sets.data);
  10983. size_t num_bitangents_read = 0, num_tangents_read = 0;
  10984. ufbxi_for (ufbxi_node, n, node->children, node->num_children) {
  10985. if (n->name[0] != 'L') continue; // All names start with 'LayerElement*'
  10986. if (n->name == ufbxi_LayerElementNormal) {
  10987. if (mesh->vertex_normal.exists) continue;
  10988. ufbxi_check(ufbxi_read_vertex_element(uc, mesh, n, (ufbx_vertex_attrib*)&mesh->vertex_normal,
  10989. ufbxi_Normals, ufbxi_NormalsIndex, ufbxi_NormalsW, 'r', 3));
  10990. } else if (n->name == ufbxi_LayerElementBinormal) {
  10991. ufbxi_tangent_layer *layer = &bitangents[num_bitangents_read++];
  10992. ufbxi_ignore(ufbxi_get_val1(n, "I", &layer->index));
  10993. ufbxi_check(ufbxi_read_vertex_element(uc, mesh, n, (ufbx_vertex_attrib*)&layer->elem,
  10994. ufbxi_Binormals, ufbxi_BinormalsIndex, ufbxi_BinormalsW, 'r', 3));
  10995. if (!layer->elem.exists) num_bitangents_read--;
  10996. } else if (n->name == ufbxi_LayerElementTangent) {
  10997. ufbxi_tangent_layer *layer = &tangents[num_tangents_read++];
  10998. ufbxi_ignore(ufbxi_get_val1(n, "I", &layer->index));
  10999. ufbxi_check(ufbxi_read_vertex_element(uc, mesh, n, (ufbx_vertex_attrib*)&layer->elem,
  11000. ufbxi_Tangents, ufbxi_TangentsIndex, ufbxi_TangentsW, 'r', 3));
  11001. if (!layer->elem.exists) num_tangents_read--;
  11002. } else if (n->name == ufbxi_LayerElementUV) {
  11003. ufbx_uv_set *set = &mesh->uv_sets.data[mesh->uv_sets.count++];
  11004. ufbxi_ignore(ufbxi_get_val1(n, "I", &set->index));
  11005. if (!ufbxi_find_val1(n, ufbxi_Name, "S", &set->name)) {
  11006. set->name = ufbx_empty_string;
  11007. }
  11008. ufbxi_check(ufbxi_read_vertex_element(uc, mesh, n, (ufbx_vertex_attrib*)&set->vertex_uv,
  11009. ufbxi_UV, ufbxi_UVIndex, NULL, 'r', 2));
  11010. if (!set->vertex_uv.exists) mesh->uv_sets.count--;
  11011. } else if (n->name == ufbxi_LayerElementColor) {
  11012. ufbx_color_set *set = &mesh->color_sets.data[mesh->color_sets.count++];
  11013. ufbxi_ignore(ufbxi_get_val1(n, "I", &set->index));
  11014. if (!ufbxi_find_val1(n, ufbxi_Name, "S", &set->name)) {
  11015. set->name = ufbx_empty_string;
  11016. }
  11017. ufbxi_check(ufbxi_read_vertex_element(uc, mesh, n, (ufbx_vertex_attrib*)&set->vertex_color,
  11018. ufbxi_Colors, ufbxi_ColorIndex, NULL, 'r', 4));
  11019. if (!set->vertex_color.exists) mesh->color_sets.count--;
  11020. } else if (n->name == ufbxi_LayerElementVertexCrease) {
  11021. ufbxi_check(ufbxi_read_vertex_element(uc, mesh, n, (ufbx_vertex_attrib*)&mesh->vertex_crease,
  11022. ufbxi_VertexCrease, ufbxi_VertexCreaseIndex, NULL, 'r', 1));
  11023. } else if (n->name == ufbxi_LayerElementEdgeCrease) {
  11024. const char *mapping = "";
  11025. ufbxi_ignore(ufbxi_find_val1(n, ufbxi_MappingInformationType, "c", (char**)&mapping));
  11026. if (mapping == ufbxi_ByEdge) {
  11027. if (mesh->edge_crease.count) continue;
  11028. ufbxi_check(ufbxi_read_truncated_array(uc, &mesh->edge_crease.data, &mesh->edge_crease.count, n, ufbxi_EdgeCrease, 'r', mesh->num_edges));
  11029. } else {
  11030. ufbxi_check(ufbxi_warn_polygon_mapping(uc, ufbxi_EdgeCrease, mapping));
  11031. }
  11032. } else if (n->name == ufbxi_LayerElementSmoothing) {
  11033. const char *mapping = "";
  11034. ufbxi_ignore(ufbxi_find_val1(n, ufbxi_MappingInformationType, "c", (char**)&mapping));
  11035. if (mapping == ufbxi_ByEdge) {
  11036. if (mesh->edge_smoothing.count) continue;
  11037. ufbxi_check(ufbxi_read_truncated_array(uc, &mesh->edge_smoothing.data, &mesh->edge_smoothing.count, n, ufbxi_Smoothing, 'b', mesh->num_edges));
  11038. } else if (mapping == ufbxi_ByPolygon) {
  11039. if (mesh->face_smoothing.count) continue;
  11040. ufbxi_check(ufbxi_read_truncated_array(uc, &mesh->face_smoothing.data, &mesh->face_smoothing.count, n, ufbxi_Smoothing, 'b', mesh->num_faces));
  11041. } else {
  11042. ufbxi_check(ufbxi_warn_polygon_mapping(uc, ufbxi_Smoothing, mapping));
  11043. }
  11044. } else if (n->name == ufbxi_LayerElementVisibility) {
  11045. const char *mapping = "";
  11046. ufbxi_ignore(ufbxi_find_val1(n, ufbxi_MappingInformationType, "c", (char**)&mapping));
  11047. if (mapping == ufbxi_ByEdge) {
  11048. if (mesh->edge_visibility.count) continue;
  11049. ufbxi_check(ufbxi_read_truncated_array(uc, &mesh->edge_visibility.data, &mesh->edge_visibility.count, n, ufbxi_Visibility, 'b', mesh->num_edges));
  11050. } else {
  11051. ufbxi_check(ufbxi_warn_polygon_mapping(uc, ufbxi_Visibility, mapping));
  11052. }
  11053. } else if (n->name == ufbxi_LayerElementMaterial) {
  11054. if (mesh->face_material.count) continue;
  11055. const char *mapping = "";
  11056. ufbxi_ignore(ufbxi_find_val1(n, ufbxi_MappingInformationType, "c", (char**)&mapping));
  11057. if (mapping == ufbxi_ByPolygon) {
  11058. ufbxi_check(ufbxi_read_truncated_array(uc, &mesh->face_material.data, &mesh->face_material.count, n, ufbxi_Materials, 'i', mesh->num_faces));
  11059. } else if (mapping == ufbxi_AllSame) {
  11060. ufbxi_value_array *arr = ufbxi_find_array(n, ufbxi_Materials, 'i');
  11061. ufbxi_check(arr && arr->size >= 1);
  11062. uint32_t material = *(uint32_t*)arr->data;
  11063. mesh->face_material.count = mesh->num_faces;
  11064. if (material == 0) {
  11065. mesh->face_material.data = (uint32_t*)ufbxi_sentinel_index_zero;
  11066. } else {
  11067. mesh->face_material.data = ufbxi_push(&uc->result, uint32_t, mesh->num_faces);
  11068. ufbxi_check(mesh->face_material.data);
  11069. ufbxi_for_list(uint32_t, p_mat, mesh->face_material) {
  11070. *p_mat = material;
  11071. }
  11072. }
  11073. } else {
  11074. ufbxi_check(ufbxi_warn_polygon_mapping(uc, ufbxi_Materials, mapping));
  11075. }
  11076. } else if (n->name == ufbxi_LayerElementPolygonGroup) {
  11077. if (mesh->face_group.count) continue;
  11078. const char *mapping = NULL;
  11079. ufbxi_check(ufbxi_find_val1(n, ufbxi_MappingInformationType, "c", (char**)&mapping));
  11080. if (mapping == ufbxi_ByPolygon) {
  11081. ufbxi_check(ufbxi_read_truncated_array(uc, &mesh->face_group.data, &mesh->face_group.count, n, ufbxi_PolygonGroup, 'i', mesh->num_faces));
  11082. }
  11083. } else if (n->name == ufbxi_LayerElementHole) {
  11084. if (mesh->face_group.count) continue;
  11085. const char *mapping = NULL;
  11086. ufbxi_check(ufbxi_find_val1(n, ufbxi_MappingInformationType, "c", (char**)&mapping));
  11087. if (mapping == ufbxi_ByPolygon) {
  11088. ufbxi_check(ufbxi_read_truncated_array(uc, &mesh->face_hole.data, &mesh->face_hole.count, n, ufbxi_Hole, 'b', mesh->num_faces));
  11089. }
  11090. } else if (!strncmp(n->name, "LayerElement", 12)) {
  11091. // Make sure the name has no internal zero bytes
  11092. ufbxi_check(!memchr(n->name, '\0', n->name_len));
  11093. // What?! 6x00 stores textures in mesh geometry, eg. "LayerElementTexture",
  11094. // "LayerElementDiffuseFactorTextures", "LayerElementEmissive_Textures"...
  11095. ufbx_string prop_name = ufbx_empty_string;
  11096. if (n->name_len > 20 && !strcmp(n->name + n->name_len - 8, "Textures")) {
  11097. prop_name.data = n->name + 12;
  11098. prop_name.length = (size_t)n->name_len - 20;
  11099. if (prop_name.data[prop_name.length - 1] == '_') {
  11100. prop_name.length -= 1;
  11101. }
  11102. } else if (!strcmp(n->name, "LayerElementTexture")) {
  11103. prop_name.data = "Diffuse";
  11104. prop_name.length = 7;
  11105. }
  11106. if (prop_name.length > 0) {
  11107. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &prop_name, false));
  11108. const char *mapping = NULL;
  11109. if (ufbxi_find_val1(n, ufbxi_MappingInformationType, "c", (char**)&mapping)) {
  11110. ufbxi_value_array *arr = ufbxi_find_array(n, ufbxi_TextureId, 'i');
  11111. ufbxi_tmp_mesh_texture *tex = ufbxi_push_zero(&uc->tmp_mesh_textures, ufbxi_tmp_mesh_texture, 1);
  11112. ufbxi_check(tex);
  11113. if (arr) {
  11114. tex->face_texture = (uint32_t*)arr->data;
  11115. tex->num_faces = arr->size;
  11116. }
  11117. tex->prop_name = prop_name;
  11118. tex->all_same = (mapping == ufbxi_AllSame);
  11119. num_textures++;
  11120. }
  11121. }
  11122. }
  11123. }
  11124. // Always use a default zero material, this will be removed if no materials are found
  11125. if (!mesh->face_material.count) {
  11126. uc->max_zero_indices = ufbxi_max_sz(uc->max_zero_indices, mesh->num_faces);
  11127. mesh->face_material.data = (uint32_t*)ufbxi_sentinel_index_zero;
  11128. mesh->face_material.count = mesh->num_faces;
  11129. }
  11130. if (uc->opts.strict) {
  11131. ufbxi_check(mesh->uv_sets.count == num_uv);
  11132. ufbxi_check(mesh->color_sets.count == num_color);
  11133. ufbxi_check(num_bitangents_read == num_bitangents);
  11134. ufbxi_check(num_tangents_read == num_tangents);
  11135. }
  11136. // Connect bitangents/tangents to UV sets
  11137. ufbxi_for (ufbxi_node, n, node->children, node->num_children) {
  11138. if (n->name != ufbxi_Layer) continue;
  11139. ufbx_uv_set *uv_set = NULL;
  11140. ufbxi_tangent_layer *bitangent_layer = NULL;
  11141. ufbxi_tangent_layer *tangent_layer = NULL;
  11142. ufbxi_for (ufbxi_node, c, n->children, n->num_children) {
  11143. uint32_t index;
  11144. const char *type;
  11145. if (c->name != ufbxi_LayerElement) continue;
  11146. if (!ufbxi_find_val1(c, ufbxi_TypedIndex, "I", &index)) continue;
  11147. if (!ufbxi_find_val1(c, ufbxi_Type, "C", (char**)&type)) continue;
  11148. if (type == ufbxi_LayerElementUV) {
  11149. ufbxi_for(ufbx_uv_set, set, mesh->uv_sets.data, mesh->uv_sets.count) {
  11150. if (set->index == index) {
  11151. uv_set = set;
  11152. break;
  11153. }
  11154. }
  11155. } else if (type == ufbxi_LayerElementBinormal) {
  11156. ufbxi_for(ufbxi_tangent_layer, layer, bitangents, num_bitangents_read) {
  11157. if (layer->index == index) {
  11158. bitangent_layer = layer;
  11159. break;
  11160. }
  11161. }
  11162. } else if (type == ufbxi_LayerElementTangent) {
  11163. ufbxi_for(ufbxi_tangent_layer, layer, tangents, num_tangents_read) {
  11164. if (layer->index == index) {
  11165. tangent_layer = layer;
  11166. break;
  11167. }
  11168. }
  11169. }
  11170. }
  11171. if (uv_set) {
  11172. if (bitangent_layer) {
  11173. uv_set->vertex_bitangent = bitangent_layer->elem;
  11174. }
  11175. if (tangent_layer) {
  11176. uv_set->vertex_tangent = tangent_layer->elem;
  11177. }
  11178. }
  11179. }
  11180. mesh->skinned_is_local = true;
  11181. mesh->skinned_position = mesh->vertex_position;
  11182. mesh->skinned_normal = mesh->vertex_normal;
  11183. ufbxi_patch_mesh_reals(mesh);
  11184. if (mesh->face_group.count > 0 && mesh->face_groups.count == 0) {
  11185. ufbxi_check(ufbxi_assign_face_groups(&uc->result, &uc->error, mesh, &uc->max_consecutive_indices, uc->retain_mesh_parts));
  11186. }
  11187. // Sort UV and color sets by set index
  11188. ufbxi_check(ufbxi_sort_uv_sets(uc, mesh->uv_sets.data, mesh->uv_sets.count));
  11189. ufbxi_check(ufbxi_sort_color_sets(uc, mesh->color_sets.data, mesh->color_sets.count));
  11190. if (num_textures > 0) {
  11191. ufbxi_mesh_extra *extra = ufbxi_push_element_extra(uc, mesh->element.element_id, ufbxi_mesh_extra);
  11192. ufbxi_check(extra);
  11193. extra->texture_count = num_textures;
  11194. extra->texture_arr = ufbxi_push_pop(&uc->tmp, &uc->tmp_mesh_textures, ufbxi_tmp_mesh_texture, num_textures);
  11195. ufbxi_check(extra->texture_arr);
  11196. }
  11197. // Subdivision
  11198. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_PreviewDivisionLevels, "I", &mesh->subdivision_preview_levels));
  11199. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_RenderDivisionLevels, "I", &mesh->subdivision_render_levels));
  11200. int32_t smoothness, boundary;
  11201. if (ufbxi_find_val1(node, ufbxi_Smoothness, "I", &smoothness)) {
  11202. if (smoothness >= 0 && smoothness <= UFBX_SUBDIVISION_DISPLAY_SMOOTH) {
  11203. mesh->subdivision_display_mode = (ufbx_subdivision_display_mode)smoothness;
  11204. }
  11205. }
  11206. if (ufbxi_find_val1(node, ufbxi_BoundaryRule, "I", &boundary)) {
  11207. if (boundary >= 0 && boundary <= UFBX_SUBDIVISION_BOUNDARY_SHARP_CORNERS - 1) {
  11208. mesh->subdivision_boundary = (ufbx_subdivision_boundary)(boundary + 1);
  11209. }
  11210. }
  11211. return 1;
  11212. }
  11213. ufbxi_noinline static ufbx_nurbs_topology ufbxi_read_nurbs_topology(const char *form)
  11214. {
  11215. if (!strcmp(form, "Open")) {
  11216. return UFBX_NURBS_TOPOLOGY_OPEN;
  11217. } else if (!strcmp(form, "Closed")) {
  11218. return UFBX_NURBS_TOPOLOGY_CLOSED;
  11219. } else if (!strcmp(form, "Periodic")) {
  11220. return UFBX_NURBS_TOPOLOGY_PERIODIC;
  11221. }
  11222. return UFBX_NURBS_TOPOLOGY_OPEN;
  11223. }
  11224. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_nurbs_curve(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11225. {
  11226. ufbx_nurbs_curve *nurbs = ufbxi_push_element(uc, info, ufbx_nurbs_curve, UFBX_ELEMENT_NURBS_CURVE);
  11227. ufbxi_check(nurbs);
  11228. int32_t dimension = 3;
  11229. const char *form = NULL;
  11230. ufbxi_check(ufbxi_find_val1(node, ufbxi_Order, "I", &nurbs->basis.order));
  11231. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_Dimension, "I", &dimension));
  11232. ufbxi_check(ufbxi_find_val1(node, ufbxi_Form, "C", (char**)&form));
  11233. nurbs->basis.topology = ufbxi_read_nurbs_topology(form);
  11234. nurbs->basis.is_2d = dimension == 2;
  11235. if (!uc->opts.ignore_geometry) {
  11236. ufbxi_value_array *points = ufbxi_find_array(node, ufbxi_Points, 'r');
  11237. ufbxi_value_array *knot = ufbxi_find_array(node, ufbxi_KnotVector, 'r');
  11238. ufbxi_check(points);
  11239. ufbxi_check(knot);
  11240. ufbxi_check(points->size % 4 == 0);
  11241. nurbs->control_points.count = points->size / 4;
  11242. nurbs->control_points.data = (ufbx_vec4*)points->data;
  11243. nurbs->basis.knot_vector.data = (ufbx_real*)knot->data;
  11244. nurbs->basis.knot_vector.count = knot->size;
  11245. }
  11246. return 1;
  11247. }
  11248. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_nurbs_surface(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11249. {
  11250. ufbx_nurbs_surface *nurbs = ufbxi_push_element(uc, info, ufbx_nurbs_surface, UFBX_ELEMENT_NURBS_SURFACE);
  11251. ufbxi_check(nurbs);
  11252. const char *form_u = NULL, *form_v = NULL;
  11253. size_t dimension_u = 0, dimension_v = 0;
  11254. int32_t step_u = 0, step_v = 0;
  11255. ufbxi_check(ufbxi_find_val2(node, ufbxi_NurbsSurfaceOrder, "II", &nurbs->basis_u.order, &nurbs->basis_v.order));
  11256. ufbxi_check(ufbxi_find_val2(node, ufbxi_Dimensions, "ZZ", &dimension_u, &dimension_v));
  11257. ufbxi_check(ufbxi_find_val2(node, ufbxi_Step, "II", &step_u, &step_v));
  11258. ufbxi_check(ufbxi_find_val2(node, ufbxi_Form, "CC", (char**)&form_u, (char**)&form_v));
  11259. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_FlipNormals, "B", &nurbs->flip_normals));
  11260. nurbs->basis_u.topology = ufbxi_read_nurbs_topology(form_u);
  11261. nurbs->basis_v.topology = ufbxi_read_nurbs_topology(form_v);
  11262. nurbs->num_control_points_u = dimension_u;
  11263. nurbs->num_control_points_v = dimension_v;
  11264. nurbs->span_subdivision_u = step_u > 0 ? (uint32_t)step_u : 4u;
  11265. nurbs->span_subdivision_v = step_v > 0 ? (uint32_t)step_v : 4u;
  11266. if (!uc->opts.ignore_geometry) {
  11267. ufbxi_value_array *points = ufbxi_find_array(node, ufbxi_Points, 'r');
  11268. ufbxi_value_array *knot_u = ufbxi_find_array(node, ufbxi_KnotVectorU, 'r');
  11269. ufbxi_value_array *knot_v = ufbxi_find_array(node, ufbxi_KnotVectorV, 'r');
  11270. ufbxi_check(points);
  11271. ufbxi_check(knot_u);
  11272. ufbxi_check(knot_v);
  11273. ufbxi_check(points->size % 4 == 0);
  11274. ufbxi_check(points->size / 4 == (size_t)dimension_u * (size_t)dimension_v);
  11275. nurbs->control_points.count = points->size / 4;
  11276. nurbs->control_points.data = (ufbx_vec4*)points->data;
  11277. nurbs->basis_u.knot_vector.data = (ufbx_real*)knot_u->data;
  11278. nurbs->basis_u.knot_vector.count = knot_u->size;
  11279. nurbs->basis_v.knot_vector.data = (ufbx_real*)knot_v->data;
  11280. nurbs->basis_v.knot_vector.count = knot_v->size;
  11281. }
  11282. return 1;
  11283. }
  11284. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_line(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11285. {
  11286. ufbx_line_curve *line = ufbxi_push_element(uc, info, ufbx_line_curve, UFBX_ELEMENT_LINE_CURVE);
  11287. ufbxi_check(line);
  11288. if (!uc->opts.ignore_geometry) {
  11289. ufbxi_value_array *points = ufbxi_find_array(node, ufbxi_Points, 'r');
  11290. ufbxi_value_array *points_index = ufbxi_find_array(node, ufbxi_PointsIndex, 'i');
  11291. ufbxi_check(points);
  11292. ufbxi_check(points_index);
  11293. ufbxi_check(points->size % 3 == 0);
  11294. if (points->size > 0) {
  11295. line->control_points.count = points->size / 3;
  11296. line->control_points.data = (ufbx_vec3*)points->data;
  11297. line->point_indices.count = points_index->size;
  11298. line->point_indices.data = (uint32_t*)points_index->data;
  11299. ufbxi_check(line->control_points.count < INT32_MAX);
  11300. // Count end points
  11301. size_t num_segments = 1;
  11302. if (line->point_indices.count > 0) {
  11303. for (size_t i = 0; i < line->point_indices.count - 1; i++) {
  11304. uint32_t ix = line->point_indices.data[i];
  11305. num_segments += (int32_t)ix < 0 ? 1u : 0u;
  11306. }
  11307. }
  11308. size_t prev_end = 0;
  11309. line->segments.data = ufbxi_push(&uc->result, ufbx_line_segment, num_segments);
  11310. ufbxi_check(line->segments.data);
  11311. for (size_t i = 0; i < line->point_indices.count; i++) {
  11312. uint32_t ix = line->point_indices.data[i];
  11313. if ((int32_t)ix < 0) {
  11314. ix = ~ix;
  11315. if (i + 1 < line->point_indices.count) {
  11316. ufbx_line_segment *segment = &line->segments.data[line->segments.count++];
  11317. segment->index_begin = (uint32_t)prev_end;
  11318. segment->num_indices = (uint32_t)(i - prev_end);
  11319. prev_end = i;
  11320. }
  11321. }
  11322. if (ix < line->control_points.count) {
  11323. line->point_indices.data[i] = ix;
  11324. } else {
  11325. ufbxi_check(ufbxi_fix_index(uc, &line->point_indices.data[i], ix, line->control_points.count));
  11326. }
  11327. }
  11328. ufbx_line_segment *segment = &line->segments.data[line->segments.count++];
  11329. segment->index_begin = (uint32_t)prev_end;
  11330. segment->num_indices = (uint32_t)ufbxi_to_size(line->point_indices.count - prev_end);
  11331. ufbx_assert(line->segments.count == num_segments);
  11332. }
  11333. }
  11334. return 1;
  11335. }
  11336. ufbxi_noinline static void ufbxi_read_transform_matrix(ufbx_matrix *m, ufbx_real *data)
  11337. {
  11338. m->m00 = data[ 0]; m->m10 = data[ 1]; m->m20 = data[ 2];
  11339. m->m01 = data[ 4]; m->m11 = data[ 5]; m->m21 = data[ 6];
  11340. m->m02 = data[ 8]; m->m12 = data[ 9]; m->m22 = data[10];
  11341. m->m03 = data[12]; m->m13 = data[13]; m->m23 = data[14];
  11342. }
  11343. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_bone(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info, const char *sub_type)
  11344. {
  11345. (void)node;
  11346. ufbx_bone *bone = ufbxi_push_element(uc, info, ufbx_bone, UFBX_ELEMENT_BONE);
  11347. ufbxi_check(bone);
  11348. if (sub_type == ufbxi_Root) {
  11349. bone->is_root = true;
  11350. }
  11351. return 1;
  11352. }
  11353. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_marker(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info, const char *sub_type, ufbx_marker_type type)
  11354. {
  11355. (void)node;
  11356. (void)sub_type;
  11357. ufbx_marker *marker = ufbxi_push_element(uc, info, ufbx_marker, UFBX_ELEMENT_MARKER);
  11358. ufbxi_check(marker);
  11359. marker->type = type;
  11360. return 1;
  11361. }
  11362. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_skin(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11363. {
  11364. ufbx_skin_deformer *skin = ufbxi_push_element(uc, info, ufbx_skin_deformer, UFBX_ELEMENT_SKIN_DEFORMER);
  11365. ufbxi_check(skin);
  11366. const char *skinning_type = NULL;
  11367. if (ufbxi_find_val1(node, ufbxi_SkinningType, "C", (char**)&skinning_type)) {
  11368. if (!strcmp(skinning_type, "Rigid")) {
  11369. skin->skinning_method = UFBX_SKINNING_METHOD_RIGID;
  11370. } else if (!strcmp(skinning_type, "Linear")) {
  11371. skin->skinning_method = UFBX_SKINNING_METHOD_LINEAR;
  11372. } else if (!strcmp(skinning_type, "DualQuaternion")) {
  11373. skin->skinning_method = UFBX_SKINNING_METHOD_DUAL_QUATERNION;
  11374. } else if (!strcmp(skinning_type, "Blend")) {
  11375. skin->skinning_method = UFBX_SKINNING_METHOD_BLENDED_DQ_LINEAR;
  11376. }
  11377. }
  11378. ufbxi_value_array *indices = ufbxi_find_array(node, ufbxi_Indexes, 'i');
  11379. ufbxi_value_array *weights = ufbxi_find_array(node, ufbxi_BlendWeights, 'r');
  11380. if (indices && weights) {
  11381. // TODO strict: ufbxi_check(indices->size == weights->size);
  11382. skin->num_dq_weights = ufbxi_min_sz(indices->size, weights->size);
  11383. skin->dq_vertices.data = (uint32_t*)indices->data;
  11384. skin->dq_weights.data = (ufbx_real*)weights->data;
  11385. skin->dq_vertices.count = skin->num_dq_weights;
  11386. skin->dq_weights.count = skin->num_dq_weights;
  11387. }
  11388. return 1;
  11389. }
  11390. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_skin_cluster(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11391. {
  11392. ufbx_skin_cluster *cluster = ufbxi_push_element(uc, info, ufbx_skin_cluster, UFBX_ELEMENT_SKIN_CLUSTER);
  11393. ufbxi_check(cluster);
  11394. ufbxi_value_array *indices = ufbxi_find_array(node, ufbxi_Indexes, 'i');
  11395. ufbxi_value_array *weights = ufbxi_find_array(node, ufbxi_Weights, 'r');
  11396. if (indices && weights) {
  11397. ufbxi_check(indices->size == weights->size);
  11398. cluster->num_weights = indices->size;
  11399. cluster->vertices.data = (uint32_t*)indices->data;
  11400. cluster->weights.data = (ufbx_real*)weights->data;
  11401. cluster->vertices.count = cluster->num_weights;
  11402. cluster->weights.count = cluster->num_weights;
  11403. }
  11404. ufbxi_value_array *transform = ufbxi_find_array(node, ufbxi_Transform, 'r');
  11405. ufbxi_value_array *transform_link = ufbxi_find_array(node, ufbxi_TransformLink, 'r');
  11406. if (transform && transform_link) {
  11407. ufbxi_check(transform->size >= 16);
  11408. ufbxi_check(transform_link->size >= 16);
  11409. ufbxi_read_transform_matrix(&cluster->mesh_node_to_bone, (ufbx_real*)transform->data);
  11410. ufbxi_read_transform_matrix(&cluster->bind_to_world, (ufbx_real*)transform_link->data);
  11411. }
  11412. return 1;
  11413. }
  11414. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_blend_channel(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11415. {
  11416. ufbx_blend_channel *channel = ufbxi_push_element(uc, info, ufbx_blend_channel, UFBX_ELEMENT_BLEND_CHANNEL);
  11417. ufbxi_check(channel);
  11418. ufbx_real_list list = { NULL, 0 };
  11419. ufbxi_value_array *full_weights = ufbxi_find_array(node, ufbxi_FullWeights, 'r');
  11420. if (full_weights) {
  11421. list.data = (ufbx_real*)full_weights->data;
  11422. list.count = full_weights->size;
  11423. }
  11424. ufbxi_check(ufbxi_push_copy(&uc->tmp_full_weights, ufbx_real_list, 1, &list));
  11425. // Blender saves blend shapes with DeformPercent as a field, not a property.
  11426. // However, the animations are mapped to the DeformPercent property.
  11427. ufbxi_node *deform_percent = ufbxi_find_child(node, ufbxi_DeformPercent);
  11428. if (channel->props.props.count == 0 && deform_percent) {
  11429. size_t num_shape_props = 1;
  11430. ufbx_prop *shape_props = ufbxi_push_zero(&uc->result, ufbx_prop, num_shape_props);
  11431. ufbxi_check(shape_props);
  11432. shape_props[0].name.data = ufbxi_DeformPercent;
  11433. shape_props[0].name.length = sizeof(ufbxi_DeformPercent) - 1;
  11434. shape_props[0]._internal_key = ufbxi_get_name_key_c(ufbxi_DeformPercent);
  11435. shape_props[0].type = UFBX_PROP_NUMBER;
  11436. shape_props[0].value_str = ufbx_empty_string;
  11437. shape_props[0].value_real = 100.0f;
  11438. ufbxi_ignore(ufbxi_get_val1(deform_percent, "R", &shape_props[0].value_real));
  11439. channel->props.props.data = shape_props;
  11440. channel->props.props.count = num_shape_props;
  11441. }
  11442. return 1;
  11443. }
  11444. typedef enum {
  11445. UFBXI_KEY_INTERPOLATION_CONSTANT = 0x2,
  11446. UFBXI_KEY_INTERPOLATION_LINEAR = 0x4,
  11447. UFBXI_KEY_INTERPOLATION_CUBIC = 0x8,
  11448. UFBXI_KEY_TANGENT_AUTO = 0x100,
  11449. UFBXI_KEY_TANGENT_TCB = 0x200,
  11450. UFBXI_KEY_TANGENT_USER = 0x400,
  11451. UFBXI_KEY_TANGENT_BROKEN = 0x800,
  11452. UFBXI_KEY_CONSTANT_NEXT = 0x100,
  11453. UFBXI_KEY_CLAMP = 0x1000,
  11454. UFBXI_KEY_TIME_INDEPENDENT = 0x2000,
  11455. UFBXI_KEY_CLAMP_PROGRESSIVE = 0x4000,
  11456. UFBXI_KEY_WEIGHTED_RIGHT = 0x1000000,
  11457. UFBXI_KEY_WEIGHTED_NEXT_LEFT = 0x2000000,
  11458. UFBXI_KEY_VELOCITY_RIGHT = 0x10000000,
  11459. UFBXI_KEY_VELOCITY_NEXT_LEFT = 0x20000000,
  11460. } ufbxi_key_flags;
  11461. static ufbxi_noinline float ufbxi_solve_auto_tangent(ufbxi_context *uc, double prev_time, double time, double next_time, ufbx_real prev_value, ufbx_real value, ufbx_real next_value, float weight_left, float weight_right, float auto_bias, uint32_t flags)
  11462. {
  11463. // Clamp tangent to zero if near either left or right key
  11464. if (flags & UFBXI_KEY_CLAMP) {
  11465. if (ufbx_fmin(ufbx_fabs(prev_value - value), ufbx_fabs(next_value - value)) <= uc->opts.key_clamp_threshold) {
  11466. return 0.0f;
  11467. }
  11468. }
  11469. // Time-independent: Set the initial slope to be the difference between the two keyframes.
  11470. double slope = (next_value - prev_value) / (next_time - prev_time);
  11471. // Non-time-independent tangents seem to blend between left/right tangent and the total difference.
  11472. if ((flags & UFBXI_KEY_TIME_INDEPENDENT) == 0) {
  11473. double slope_left = (value - prev_value) / (time - prev_time);
  11474. double slope_right = (next_value - value) / (next_time - time);
  11475. double delta = (time - prev_time) / (next_time - prev_time);
  11476. slope = slope * 0.5 + (slope_left * (1.0 - delta) + slope_right * delta) * 0.5;
  11477. double bias_weight = ufbx_fabs(auto_bias) / 100.0;
  11478. if (bias_weight > 0.0001) {
  11479. double bias_target = auto_bias > 0.0 ? slope_right : slope_left;
  11480. double bias_delta = bias_target - slope;
  11481. slope = slope * (1.0 - bias_weight) + bias_target * bias_weight;
  11482. // Auto bias larger than 500 (positive or negative) adds an absolute
  11483. // value to the slope, determined by `((bias-500) / 100)^2 * 40`.
  11484. double abs_bias_weight = bias_weight - 5.0;
  11485. if (abs_bias_weight > 0.0) {
  11486. double bias_sign = ufbx_fabs(bias_delta) > 0.00001 ? bias_delta : auto_bias;
  11487. bias_sign = bias_sign > 0.0 ? 1.0 : -1.0;
  11488. slope += abs_bias_weight * abs_bias_weight * bias_sign * 40.0;
  11489. }
  11490. }
  11491. }
  11492. // Prevent overshooting by clamping the slope in case either
  11493. // tangent goes above/below the endpoints.
  11494. if (flags & UFBXI_KEY_CLAMP_PROGRESSIVE) {
  11495. // Split the slope to sign and a non-negative absolute value
  11496. double slope_sign = slope >= 0.0 ? 1.0 : -1.0;
  11497. double abs_slope = slope_sign * slope;
  11498. // Find limits for the absolute value of the slope
  11499. double range_left = weight_left * (time - prev_time);
  11500. double range_right = weight_right * (next_time - time);
  11501. double max_left = range_left > 0.0 ? slope_sign * (value - prev_value) / range_left : 0.0;
  11502. double max_right = range_right > 0.0 ? slope_sign * (next_value - value) / range_right : 0.0;
  11503. // Clamp negative values and NaNs to zero
  11504. if (!(max_left > 0.0)) max_left = 0.0;
  11505. if (!(max_right > 0.0)) max_right = 0.0;
  11506. // Clamp the absolute slope from both sides
  11507. if (abs_slope > max_left) abs_slope = max_left;
  11508. if (abs_slope > max_right) abs_slope = max_right;
  11509. slope = (slope_sign * abs_slope);
  11510. }
  11511. return (float)slope;
  11512. }
  11513. static float ufbxi_solve_auto_tangent_left(ufbxi_context *uc, double prev_time, double time, ufbx_real prev_value, ufbx_real value, float weight_left, float auto_bias, uint32_t flags)
  11514. {
  11515. (void)weight_left;
  11516. if (flags & UFBXI_KEY_CLAMP_PROGRESSIVE) return 0.0f;
  11517. if (flags & UFBXI_KEY_CLAMP) {
  11518. if (ufbx_fabs(prev_value - value) <= uc->opts.key_clamp_threshold) {
  11519. return 0.0f;
  11520. }
  11521. }
  11522. double slope = (value - prev_value) / (time - prev_time);
  11523. if ((flags & UFBXI_KEY_TIME_INDEPENDENT) == 0) {
  11524. double abs_bias_weight = ufbx_fabs(auto_bias) / 100.0 - 5.0;
  11525. if (abs_bias_weight > 0.0) {
  11526. double bias_sign = auto_bias > 0.0 ? 1.0 : -1.0;
  11527. slope += abs_bias_weight * abs_bias_weight * bias_sign * 40.0;
  11528. }
  11529. }
  11530. return (float)slope;
  11531. }
  11532. static float ufbxi_solve_auto_tangent_right(ufbxi_context *uc, double time, double next_time, ufbx_real value, ufbx_real next_value, float weight_right, float auto_bias, uint32_t flags)
  11533. {
  11534. (void)weight_right;
  11535. if (flags & UFBXI_KEY_CLAMP_PROGRESSIVE) return 0.0f;
  11536. if (flags & UFBXI_KEY_CLAMP) {
  11537. if (ufbx_fabs(next_value - value) <= uc->opts.key_clamp_threshold) {
  11538. return 0.0f;
  11539. }
  11540. }
  11541. double slope = (next_value - value) / (next_time - time);
  11542. if ((flags & UFBXI_KEY_TIME_INDEPENDENT) == 0) {
  11543. double abs_bias_weight = ufbx_fabs(auto_bias) / 100.0 - 5.0;
  11544. if (abs_bias_weight > 0.0) {
  11545. double bias_sign = auto_bias > 0.0 ? 1.0 : -1.0;
  11546. slope += abs_bias_weight * abs_bias_weight * bias_sign * 40.0;
  11547. }
  11548. }
  11549. return (float)slope;
  11550. }
  11551. static void ufbxi_solve_tcb(float *p_slope_left, float *p_slope_right, double tension, double continuity, double bias, double slope_left, double slope_right, bool edge)
  11552. {
  11553. double factor = edge ? 1.0 : 0.5;
  11554. double d00 = factor * (1.0 - tension) * (1.0 + bias) * (1.0 - continuity);
  11555. double d01 = factor * (1.0 - tension) * (1.0 - bias) * (1.0 + continuity);
  11556. double d10 = factor * (1.0 - tension) * (1.0 + bias) * (1.0 + continuity);
  11557. double d11 = factor * (1.0 - tension) * (1.0 - bias) * (1.0 - continuity);
  11558. *p_slope_left = (float)(d00 * slope_left + d01 * slope_right);
  11559. *p_slope_right = (float)(d10 * slope_left + d11 * slope_right);
  11560. }
  11561. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_animation_curve(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11562. {
  11563. ufbx_anim_curve *curve = ufbxi_push_element(uc, info, ufbx_anim_curve, UFBX_ELEMENT_ANIM_CURVE);
  11564. ufbxi_check(curve);
  11565. if (uc->opts.ignore_animation) return 1;
  11566. ufbxi_value_array *times, *values, *attr_flags, *attrs, *refs;
  11567. ufbxi_check(times = ufbxi_find_array(node, ufbxi_KeyTime, 'l'));
  11568. ufbxi_check(values = ufbxi_find_array(node, ufbxi_KeyValueFloat, 'r'));
  11569. ufbxi_check(attr_flags = ufbxi_find_array(node, ufbxi_KeyAttrFlags, 'i'));
  11570. ufbxi_check(attrs = ufbxi_find_array(node, ufbxi_KeyAttrDataFloat, '?'));
  11571. ufbxi_check(refs = ufbxi_find_array(node, ufbxi_KeyAttrRefCount, 'i'));
  11572. // Time and value arrays that define the keyframes should be parallel
  11573. ufbxi_check(times->size == values->size);
  11574. // Flags and attributes are run-length encoded where KeyAttrRefCount (refs)
  11575. // is an array that describes how many times to repeat a given flag/attribute.
  11576. // Attributes consist of 4 32-bit floating point values per key.
  11577. ufbxi_check(attr_flags->size == refs->size);
  11578. ufbxi_check(attrs->size == refs->size * 4u);
  11579. size_t num_keys = times->size;
  11580. ufbx_keyframe *keys = ufbxi_push(&uc->result, ufbx_keyframe, num_keys);
  11581. ufbxi_check(keys);
  11582. curve->keyframes.data = keys;
  11583. curve->keyframes.count = num_keys;
  11584. int64_t *p_time = (int64_t*)times->data;
  11585. ufbx_real *p_value = (ufbx_real*)values->data;
  11586. int32_t *p_flag = (int32_t*)attr_flags->data;
  11587. float *p_attr = (float*)attrs->data;
  11588. int32_t *p_ref = (int32_t*)refs->data, *p_ref_end = p_ref + refs->size;
  11589. // The previous key defines the weight/slope of the left tangent
  11590. float slope_left = 0.0f;
  11591. float weight_left = 0.333333f;
  11592. // float velocity_left = 0.0f;
  11593. double prev_time = 0.0;
  11594. double next_time = 0.0;
  11595. int32_t refs_left = 0;
  11596. if (num_keys > 0) {
  11597. next_time = (double)p_time[0] / uc->ktime_sec_double;
  11598. if (p_ref < p_ref_end) refs_left = *p_ref;
  11599. }
  11600. for (size_t i = 0; i < num_keys; i++) {
  11601. ufbx_keyframe *key = &keys[i];
  11602. ufbxi_check(refs_left > 0);
  11603. ufbx_real value = *p_value;
  11604. if (i == 0) {
  11605. curve->min_value = value;
  11606. curve->max_value = value;
  11607. } else {
  11608. curve->min_value = ufbxi_min_real(curve->min_value, value);
  11609. curve->max_value = ufbxi_max_real(curve->max_value, value);
  11610. }
  11611. key->time = next_time;
  11612. key->value = value;
  11613. if (i + 1 < num_keys) {
  11614. next_time = (double)p_time[1] / uc->ktime_sec_double;
  11615. }
  11616. uint32_t flags = (uint32_t)*p_flag;
  11617. float slope_right = p_attr[0];
  11618. float weight_right = 0.333333f;
  11619. //float velocity_right = 0.0f;
  11620. float next_slope_left = p_attr[1];
  11621. float next_weight_left = 0.333333f;
  11622. // float next_velocity_left = 0.0f;
  11623. if ((flags & (UFBXI_KEY_WEIGHTED_RIGHT|UFBXI_KEY_WEIGHTED_NEXT_LEFT)) != 0) {
  11624. // At least one of the tangents is weighted. The weights are encoded as
  11625. // two 0.4 _decimal_ fixed point values that are packed into 32 bits and
  11626. // interpreted as a 32-bit float.
  11627. uint32_t packed_weights;
  11628. memcpy(&packed_weights, &p_attr[2], sizeof(uint32_t));
  11629. if (flags & UFBXI_KEY_WEIGHTED_RIGHT) {
  11630. // Right tangent is weighted
  11631. weight_right = (float)(packed_weights & 0xffff) * 0.0001f;
  11632. }
  11633. if (flags & UFBXI_KEY_WEIGHTED_NEXT_LEFT) {
  11634. // Next left tangent is weighted
  11635. next_weight_left = (float)(packed_weights >> 16) * 0.0001f;
  11636. }
  11637. }
  11638. #if 0
  11639. if ((flags & (UFBXI_KEY_VELOCITY_RIGHT|UFBXI_KEY_VELOCITY_NEXT_LEFT)) != 0) {
  11640. // Velocities are encoded in the same way as weights, see above.
  11641. uint32_t packed_velocities;
  11642. memcpy(&packed_velocities, &p_attr[3], sizeof(uint32_t));
  11643. if (flags & UFBXI_KEY_VELOCITY_RIGHT) {
  11644. // Right tangent has velocity
  11645. velocity_right = (float)(int16_t)(packed_velocities & 0xffff) * 0.0001f;
  11646. }
  11647. if (flags & UFBXI_KEY_VELOCITY_NEXT_LEFT) {
  11648. // Next left tangent has velocity
  11649. next_velocity_left = (float)(int16_t)(packed_velocities >> 16) * 0.0001f;
  11650. }
  11651. }
  11652. #endif
  11653. if (flags & UFBXI_KEY_INTERPOLATION_CONSTANT) {
  11654. // Constant interpolation: Set cubic tangents to flat.
  11655. if (flags & UFBXI_KEY_CONSTANT_NEXT) {
  11656. // Take constant value from next key
  11657. key->interpolation = UFBX_INTERPOLATION_CONSTANT_NEXT;
  11658. } else {
  11659. // Take constant value from the previous key
  11660. key->interpolation = UFBX_INTERPOLATION_CONSTANT_PREV;
  11661. }
  11662. weight_right = next_weight_left = 0.333333f;
  11663. slope_right = next_slope_left = 0.0f;
  11664. } else if (flags & UFBXI_KEY_INTERPOLATION_CUBIC) {
  11665. // Cubic interpolation
  11666. key->interpolation = UFBX_INTERPOLATION_CUBIC;
  11667. if (flags & UFBXI_KEY_TANGENT_TCB) {
  11668. double tcb_slope_left = 0.0;
  11669. double tcb_slope_right = 0.0;
  11670. bool tcb_edge = false;
  11671. if (i > 0 && key->time > prev_time) {
  11672. tcb_slope_left = (key->value - p_value[-1]) / (key->time - prev_time);
  11673. } else {
  11674. tcb_edge = true;
  11675. }
  11676. if (i + 1 < num_keys && next_time > key->time) {
  11677. tcb_slope_right = (p_value[1] - key->value) / (next_time - key->time);
  11678. } else {
  11679. tcb_edge = true;
  11680. }
  11681. ufbxi_solve_tcb(&slope_left, &slope_right, p_attr[0], p_attr[1], p_attr[2], tcb_slope_left, tcb_slope_right, tcb_edge);
  11682. // TODO: How to handle these?
  11683. next_slope_left = 0.0f;
  11684. next_weight_left = 0.333333f;
  11685. // next_velocity_left = 0.0f;
  11686. } else if (flags & UFBXI_KEY_TANGENT_USER) {
  11687. // User tangents
  11688. if (flags & UFBXI_KEY_TANGENT_BROKEN) {
  11689. // Broken tangents: No need to modify slopes
  11690. } else {
  11691. // Unified tangents: Use right slope for both sides
  11692. // TODO: ??? slope_left = slope_right;
  11693. }
  11694. } else {
  11695. // TODO: Auto break (0x800)
  11696. if (i > 0 && i + 1 < num_keys && key->time > prev_time && next_time > key->time) {
  11697. if (ufbx_fabs(slope_left + slope_right) <= 0.0001f) {
  11698. slope_left = slope_right = ufbxi_solve_auto_tangent(uc,
  11699. prev_time, key->time, next_time,
  11700. p_value[-1], key->value, p_value[1],
  11701. weight_left, weight_right, slope_right, flags);
  11702. } else {
  11703. slope_left = ufbxi_solve_auto_tangent(uc,
  11704. prev_time, key->time, next_time,
  11705. p_value[-1], key->value, p_value[1],
  11706. weight_left, weight_right, -slope_left, flags);
  11707. slope_right = ufbxi_solve_auto_tangent(uc,
  11708. prev_time, key->time, next_time,
  11709. p_value[-1], key->value, p_value[1],
  11710. weight_left, weight_right, slope_right, flags);
  11711. }
  11712. } else if (i > 0 && key->time > prev_time) {
  11713. slope_left = slope_right = ufbxi_solve_auto_tangent_left(uc,
  11714. prev_time, key->time,
  11715. p_value[-1], key->value,
  11716. weight_left, -slope_left, flags);
  11717. } else if (i + 1 < num_keys && next_time > key->time) {
  11718. slope_left = slope_right = ufbxi_solve_auto_tangent_right(uc,
  11719. key->time, next_time,
  11720. key->value, p_value[1],
  11721. weight_right, slope_right, flags);
  11722. } else {
  11723. // Only / invalid keyframe: Set both slopes to zero
  11724. slope_left = slope_right = 0.0f;
  11725. }
  11726. // ??? Looks like at least MotionBuilder adjusts weight and auto bias to
  11727. // implement velocity and the velocity information in the file is purely
  11728. // for UI (?) If auto bias is not accounted for the velocity computation
  11729. // below results in the correct tangents, but with auto bias the velocity
  11730. // seems to be accounted for twice resulting in incorrect values...
  11731. #if 0
  11732. if (weight_left >= UFBX_EPSILON) {
  11733. slope_left *= (float)(1.0 - ufbx_fmin(velocity_left / weight_left, 1.0));
  11734. }
  11735. if (weight_right >= UFBX_EPSILON) {
  11736. slope_right *= (float)(1.0 - ufbx_fmin(velocity_right / weight_right, 1.0));
  11737. }
  11738. #endif
  11739. }
  11740. } else {
  11741. // Linear or unknown interpolation: Set cubic tangents to match
  11742. // the linear interpolation with weights of 1/3.
  11743. key->interpolation = UFBX_INTERPOLATION_LINEAR;
  11744. weight_right = 0.333333f;
  11745. next_weight_left = 0.333333f;
  11746. if (next_time > key->time) {
  11747. double delta_time = next_time - key->time;
  11748. if (delta_time > 0.0) {
  11749. double slope = (p_value[1] - key->value) / delta_time;
  11750. slope_right = next_slope_left = (float)slope;
  11751. } else {
  11752. slope_right = next_slope_left = 0.0f;
  11753. }
  11754. } else {
  11755. slope_right = next_slope_left = 0.0f;
  11756. }
  11757. }
  11758. // Set the tangents based on weights (dx relative to the time difference
  11759. // between the previous/next key) and slope (simply d = slope * dx)
  11760. if (key->time > prev_time) {
  11761. double delta = key->time - prev_time;
  11762. key->left.dx = (float)(weight_left * delta);
  11763. key->left.dy = key->left.dx * slope_left;
  11764. } else {
  11765. key->left.dx = 0.0f;
  11766. key->left.dy = 0.0f;
  11767. }
  11768. if (next_time > key->time) {
  11769. double delta = next_time - key->time;
  11770. key->right.dx = (float)(weight_right * delta);
  11771. key->right.dy = key->right.dx * slope_right;
  11772. } else {
  11773. key->right.dx = 0.0f;
  11774. key->right.dy = 0.0f;
  11775. }
  11776. slope_left = next_slope_left;
  11777. weight_left = next_weight_left;
  11778. // velocity_left = next_velocity_left;
  11779. prev_time = key->time;
  11780. // Decrement attribute refcount and potentially move to the next one.
  11781. if (--refs_left == 0) {
  11782. p_flag++;
  11783. p_attr += 4;
  11784. p_ref++;
  11785. if (p_ref < p_ref_end) refs_left = *p_ref;
  11786. }
  11787. p_time++;
  11788. p_value++;
  11789. }
  11790. return 1;
  11791. }
  11792. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_material(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11793. {
  11794. ufbx_material *material = ufbxi_push_element(uc, info, ufbx_material, UFBX_ELEMENT_MATERIAL);
  11795. ufbxi_check(material);
  11796. if (!ufbxi_find_val1(node, ufbxi_ShadingModel, "S", &material->shading_model_name)) {
  11797. material->shading_model_name = ufbx_empty_string;
  11798. }
  11799. material->shader_prop_prefix = ufbx_empty_string;
  11800. return 1;
  11801. }
  11802. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_texture(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11803. {
  11804. ufbx_texture *texture = ufbxi_push_element(uc, info, ufbx_texture, UFBX_ELEMENT_TEXTURE);
  11805. ufbxi_check(texture);
  11806. texture->type = UFBX_TEXTURE_FILE;
  11807. texture->filename = ufbx_empty_string;
  11808. texture->absolute_filename = ufbx_empty_string;
  11809. texture->relative_filename = ufbx_empty_string;
  11810. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_FileName, "S", &texture->absolute_filename));
  11811. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_Filename, "S", &texture->absolute_filename));
  11812. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_RelativeFileName, "S", &texture->relative_filename));
  11813. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_RelativeFilename, "S", &texture->relative_filename));
  11814. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_FileName, "b", &texture->raw_absolute_filename));
  11815. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_Filename, "b", &texture->raw_absolute_filename));
  11816. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_RelativeFileName, "b", &texture->raw_relative_filename));
  11817. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_RelativeFilename, "b", &texture->raw_relative_filename));
  11818. return 1;
  11819. }
  11820. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_layered_texture(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11821. {
  11822. ufbx_texture *texture = ufbxi_push_element(uc, info, ufbx_texture, UFBX_ELEMENT_TEXTURE);
  11823. ufbxi_check(texture);
  11824. texture->type = UFBX_TEXTURE_LAYERED;
  11825. texture->filename = ufbx_empty_string;
  11826. texture->absolute_filename = ufbx_empty_string;
  11827. texture->relative_filename = ufbx_empty_string;
  11828. ufbxi_texture_extra *extra = ufbxi_push_element_extra(uc, texture->element.element_id, ufbxi_texture_extra);
  11829. ufbxi_check(extra);
  11830. ufbxi_value_array *alphas = ufbxi_find_array(node, ufbxi_Alphas, 'r');
  11831. if (alphas) {
  11832. extra->alphas = (ufbx_real*)alphas->data;
  11833. extra->num_alphas = alphas->size;
  11834. }
  11835. ufbxi_value_array *blend_modes = ufbxi_find_array(node, ufbxi_BlendModes, 'i');
  11836. if (blend_modes) {
  11837. extra->blend_modes = (int32_t*)blend_modes->data;
  11838. extra->num_blend_modes = blend_modes->size;
  11839. }
  11840. return 1;
  11841. }
  11842. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_video(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11843. {
  11844. ufbx_video *video = ufbxi_push_element(uc, info, ufbx_video, UFBX_ELEMENT_VIDEO);
  11845. ufbxi_check(video);
  11846. video->filename = ufbx_empty_string;
  11847. video->absolute_filename = ufbx_empty_string;
  11848. video->relative_filename = ufbx_empty_string;
  11849. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_FileName, "S", &video->absolute_filename));
  11850. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_Filename, "S", &video->absolute_filename));
  11851. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_RelativeFileName, "S", &video->relative_filename));
  11852. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_RelativeFilename, "S", &video->relative_filename));
  11853. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_FileName, "b", &video->raw_absolute_filename));
  11854. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_Filename, "b", &video->raw_absolute_filename));
  11855. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_RelativeFileName, "b", &video->raw_relative_filename));
  11856. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_RelativeFilename, "b", &video->raw_relative_filename));
  11857. ufbxi_node *content_node = ufbxi_find_child(node, ufbxi_Content);
  11858. ufbxi_check(ufbxi_read_embedded_blob(uc, &video->content, content_node));
  11859. return 1;
  11860. }
  11861. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_anim_stack(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11862. {
  11863. (void)node;
  11864. ufbx_anim_stack *stack = ufbxi_push_element(uc, info, ufbx_anim_stack, UFBX_ELEMENT_ANIM_STACK);
  11865. ufbxi_check(stack);
  11866. uint32_t hash = ufbxi_hash_ptr(info->name.data);
  11867. ufbxi_tmp_anim_stack *entry = ufbxi_map_find(&uc->anim_stack_map, ufbxi_tmp_anim_stack, hash, &info->name.data);
  11868. if (!entry) {
  11869. entry = ufbxi_map_insert(&uc->anim_stack_map, ufbxi_tmp_anim_stack, hash, &info->name.data);
  11870. ufbxi_check(entry);
  11871. entry->name = info->name.data;
  11872. entry->stack = stack;
  11873. }
  11874. return 1;
  11875. }
  11876. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_pose(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info, const char *sub_type)
  11877. {
  11878. ufbx_pose *pose = ufbxi_push_element(uc, info, ufbx_pose, UFBX_ELEMENT_POSE);
  11879. ufbxi_check(pose);
  11880. // TODO: What are the actual other types?
  11881. pose->is_bind_pose = sub_type == ufbxi_BindPose;
  11882. size_t num_bones = 0;
  11883. ufbxi_for(ufbxi_node, n, node->children, node->num_children) {
  11884. if (n->name != ufbxi_PoseNode) continue;
  11885. // Bones are linked with FBX names/IDs bypassing the connection system (!?)
  11886. uint64_t fbx_id = 0;
  11887. if (uc->version < 7000) {
  11888. char *name = NULL;
  11889. if (!ufbxi_find_val1(n, ufbxi_Node, "c", &name)) continue;
  11890. fbx_id = ufbxi_synthetic_id_from_string(name);
  11891. } else {
  11892. if (!ufbxi_find_val1(n, ufbxi_Node, "L", &fbx_id)) continue;
  11893. }
  11894. ufbxi_value_array *matrix = ufbxi_find_array(n, ufbxi_Matrix, 'r');
  11895. if (!matrix) continue;
  11896. ufbxi_check(matrix->size >= 16);
  11897. ufbxi_tmp_bone_pose *tmp_pose = ufbxi_push(&uc->tmp_stack, ufbxi_tmp_bone_pose, 1);
  11898. ufbxi_check(tmp_pose);
  11899. num_bones++;
  11900. tmp_pose->bone_fbx_id = fbx_id;
  11901. ufbxi_read_transform_matrix(&tmp_pose->bone_to_world, (ufbx_real*)matrix->data);
  11902. }
  11903. // HACK: Transport `ufbxi_tmp_bone_pose` array through the `ufbx_bone_pose` pointer
  11904. pose->bone_poses.count = num_bones;
  11905. pose->bone_poses.data = (ufbx_bone_pose*)ufbxi_push_pop(&uc->tmp, &uc->tmp_stack, ufbxi_tmp_bone_pose, num_bones);
  11906. ufbxi_check(pose->bone_poses.data);
  11907. return 1;
  11908. }
  11909. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_shader_prop_bindings(ufbxi_context *uc, ufbx_shader_prop_binding *bindings, size_t count)
  11910. {
  11911. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_shader_prop_binding)));
  11912. ufbxi_macro_stable_sort(ufbx_shader_prop_binding, 32, bindings, uc->tmp_arr, count,
  11913. ( ufbxi_str_less(a->shader_prop, b->shader_prop) ) );
  11914. return 1;
  11915. }
  11916. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_binding_table(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11917. {
  11918. ufbx_shader_binding *bindings = ufbxi_push_element(uc, info, ufbx_shader_binding, UFBX_ELEMENT_SHADER_BINDING);
  11919. ufbxi_check(bindings);
  11920. size_t num_entries = 0;
  11921. ufbxi_for (ufbxi_node, n, node->children, node->num_children) {
  11922. if (n->name != ufbxi_Entry) continue;
  11923. ufbx_string src, dst;
  11924. const char *src_type = NULL, *dst_type = NULL;
  11925. if (!ufbxi_get_val4(n, "SCSC", &src, (char**)&src_type, &dst, (char**)&dst_type)) {
  11926. continue;
  11927. }
  11928. if (src_type == ufbxi_FbxPropertyEntry && dst_type == ufbxi_FbxSemanticEntry) {
  11929. ufbx_shader_prop_binding *bind = ufbxi_push(&uc->tmp_stack, ufbx_shader_prop_binding, 1);
  11930. ufbxi_check(bind);
  11931. bind->material_prop = src;
  11932. bind->shader_prop = dst;
  11933. num_entries++;
  11934. } else if (src_type == ufbxi_FbxSemanticEntry && dst_type == ufbxi_FbxPropertyEntry) {
  11935. ufbx_shader_prop_binding *bind = ufbxi_push(&uc->tmp_stack, ufbx_shader_prop_binding, 1);
  11936. ufbxi_check(bind);
  11937. bind->material_prop = dst;
  11938. bind->shader_prop = src;
  11939. num_entries++;
  11940. }
  11941. }
  11942. bindings->prop_bindings.count = num_entries;
  11943. bindings->prop_bindings.data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_shader_prop_binding, num_entries);
  11944. ufbxi_check(bindings->prop_bindings.data);
  11945. ufbxi_check(ufbxi_sort_shader_prop_bindings(uc, bindings->prop_bindings.data, bindings->prop_bindings.count));
  11946. return 1;
  11947. }
  11948. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_selection_set(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11949. {
  11950. (void)node;
  11951. ufbx_selection_set *set = ufbxi_push_element(uc, info, ufbx_selection_set, UFBX_ELEMENT_SELECTION_SET);
  11952. ufbxi_check(set);
  11953. return 1;
  11954. }
  11955. ufbxi_noinline static void ufbxi_find_uint32_list(ufbx_uint32_list *dst, ufbxi_node *node, const char *name)
  11956. {
  11957. ufbxi_value_array *arr = ufbxi_find_array(node, name, 'i');
  11958. if (arr) {
  11959. dst->data = (uint32_t*)arr->data;
  11960. dst->count = arr->size;
  11961. }
  11962. }
  11963. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_selection_node(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11964. {
  11965. ufbx_selection_node *sel = ufbxi_push_element(uc, info, ufbx_selection_node, UFBX_ELEMENT_SELECTION_NODE);
  11966. ufbxi_check(sel);
  11967. int32_t in_set = 0;
  11968. if (ufbxi_find_val1(node, ufbxi_IsTheNodeInSet, "I", &in_set) && in_set) {
  11969. sel->include_node = true;
  11970. }
  11971. ufbxi_find_uint32_list(&sel->vertices, node, ufbxi_VertexIndexArray);
  11972. ufbxi_find_uint32_list(&sel->edges, node, ufbxi_EdgeIndexArray);
  11973. ufbxi_find_uint32_list(&sel->faces, node, ufbxi_PolygonIndexArray);
  11974. return 1;
  11975. }
  11976. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_character(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11977. {
  11978. (void)node;
  11979. ufbx_character *character = ufbxi_push_element(uc, info, ufbx_character, UFBX_ELEMENT_CHARACTER);
  11980. ufbxi_check(character);
  11981. // TODO: There's some extremely cursed all-caps data in characters
  11982. return 1;
  11983. }
  11984. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_audio_clip(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  11985. {
  11986. ufbx_audio_clip *audio = ufbxi_push_element(uc, info, ufbx_audio_clip, UFBX_ELEMENT_AUDIO_CLIP);
  11987. ufbxi_check(audio);
  11988. audio->filename = ufbx_empty_string;
  11989. audio->absolute_filename = ufbx_empty_string;
  11990. audio->relative_filename = ufbx_empty_string;
  11991. ufbxi_node *content_node = ufbxi_find_child(node, ufbxi_Content);
  11992. ufbxi_check(ufbxi_read_embedded_blob(uc, &audio->content, content_node));
  11993. return 1;
  11994. }
  11995. typedef struct {
  11996. ufbx_constraint_type type;
  11997. const char *name;
  11998. } ufbxi_constraint_type;
  11999. static const ufbxi_constraint_type ufbxi_constraint_types[] = {
  12000. { UFBX_CONSTRAINT_AIM, "Aim" },
  12001. { UFBX_CONSTRAINT_PARENT, "Parent-Child" },
  12002. { UFBX_CONSTRAINT_POSITION, "Position From Positions" },
  12003. { UFBX_CONSTRAINT_ROTATION, "Rotation From Rotations" },
  12004. { UFBX_CONSTRAINT_SCALE, "Scale From Scales" },
  12005. { UFBX_CONSTRAINT_SINGLE_CHAIN_IK, "Single Chain IK" },
  12006. };
  12007. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_constraint(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  12008. {
  12009. (void)node;
  12010. ufbx_constraint *constraint = ufbxi_push_element(uc, info, ufbx_constraint, UFBX_ELEMENT_CONSTRAINT);
  12011. ufbxi_check(constraint);
  12012. if (!ufbxi_find_val1(node, ufbxi_Type, "S", &constraint->type_name)) {
  12013. constraint->type_name = ufbx_empty_string;
  12014. }
  12015. ufbxi_for(const ufbxi_constraint_type, ctype, ufbxi_constraint_types, ufbxi_arraycount(ufbxi_constraint_types)) {
  12016. if (!strcmp(constraint->type_name.data, ctype->name)) {
  12017. constraint->type = ctype->type;
  12018. break;
  12019. }
  12020. }
  12021. // TODO: There's some extremely cursed all-caps data in characters
  12022. return 1;
  12023. }
  12024. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_synthetic_attribute(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info, ufbx_string type_str, const char *sub_type, const char *super_type)
  12025. {
  12026. if ((sub_type == ufbxi_empty_char || sub_type == ufbxi_Model) && type_str.data == ufbxi_Model) {
  12027. // Plain model
  12028. return 1;
  12029. }
  12030. ufbxi_element_info attrib_info = *info;
  12031. ufbxi_check(ufbxi_push_synthetic_id(uc, &attrib_info.fbx_id));
  12032. // Use type and name from NodeAttributeName if it exists *uniquely*
  12033. ufbx_string type_and_name;
  12034. if (ufbxi_find_val1(node, ufbxi_NodeAttributeName, "s", &type_and_name)) {
  12035. ufbx_string attrib_type_str, attrib_name_str;
  12036. ufbxi_check(ufbxi_split_type_and_name(uc, type_and_name, &attrib_type_str, &attrib_name_str));
  12037. if (attrib_name_str.length > 0) {
  12038. attrib_info.name = attrib_name_str;
  12039. uint64_t attrib_id = ufbxi_synthetic_id_from_string(type_and_name.data);
  12040. if (info->fbx_id != attrib_id && !ufbxi_fbx_id_exists(uc, attrib_id)) {
  12041. attrib_info.fbx_id = attrib_id;
  12042. }
  12043. }
  12044. }
  12045. // 6x00: Link the node to the node attribute so property connections can be
  12046. // redirected from connections if necessary.
  12047. if (uc->version < 7000) {
  12048. ufbxi_check(ufbxi_insert_fbx_attr(uc, info->fbx_id, attrib_info.fbx_id));
  12049. // Split properties between the node and the attribute
  12050. ufbx_prop *ps = info->props.props.data;
  12051. size_t dst = 0, src = 0, end = info->props.props.count;
  12052. while (src < end) {
  12053. if (!ufbxi_is_node_property(uc, ps[src].name.data)) {
  12054. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_prop, 1, &ps[src]));
  12055. src++;
  12056. } else if (dst != src) {
  12057. ps[dst++] = ps[src++];
  12058. } else {
  12059. dst++; src++;
  12060. }
  12061. }
  12062. attrib_info.props.props.count = end - dst;
  12063. attrib_info.props.props.data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_prop, attrib_info.props.props.count);
  12064. ufbxi_check(attrib_info.props.props.data);
  12065. info->props.props.count = dst;
  12066. }
  12067. if (sub_type == ufbxi_Mesh) {
  12068. ufbxi_check(ufbxi_read_mesh(uc, node, &attrib_info));
  12069. } else if (sub_type == ufbxi_Light) {
  12070. ufbxi_check(ufbxi_read_element(uc, node, &attrib_info, sizeof(ufbx_light), UFBX_ELEMENT_LIGHT));
  12071. } else if (sub_type == ufbxi_Camera) {
  12072. ufbxi_check(ufbxi_read_element(uc, node, &attrib_info, sizeof(ufbx_camera), UFBX_ELEMENT_CAMERA));
  12073. } else if (sub_type == ufbxi_LimbNode || sub_type == ufbxi_Limb || sub_type == ufbxi_Root) {
  12074. ufbxi_check(ufbxi_read_bone(uc, node, &attrib_info, sub_type));
  12075. } else if (sub_type == ufbxi_Null || sub_type == ufbxi_Marker) {
  12076. ufbxi_check(ufbxi_read_element(uc, node, &attrib_info, sizeof(ufbx_empty), UFBX_ELEMENT_EMPTY));
  12077. } else if (sub_type == ufbxi_NurbsCurve) {
  12078. if (!ufbxi_find_child(node, ufbxi_KnotVector)) return 1;
  12079. ufbxi_check(ufbxi_read_nurbs_curve(uc, node, &attrib_info));
  12080. } else if (sub_type == ufbxi_NurbsSurface) {
  12081. if (!ufbxi_find_child(node, ufbxi_KnotVectorU)) return 1;
  12082. if (!ufbxi_find_child(node, ufbxi_KnotVectorV)) return 1;
  12083. ufbxi_check(ufbxi_read_nurbs_surface(uc, node, &attrib_info));
  12084. } else if (sub_type == ufbxi_Line) {
  12085. if (!ufbxi_find_child(node, ufbxi_Points)) return 1;
  12086. if (!ufbxi_find_child(node, ufbxi_PointsIndex)) return 1;
  12087. ufbxi_check(ufbxi_read_line(uc, node, &attrib_info));
  12088. } else if (sub_type == ufbxi_TrimNurbsSurface) {
  12089. if (!ufbxi_find_child(node, ufbxi_Layer)) return 1;
  12090. ufbxi_check(ufbxi_read_element(uc, node, &attrib_info, sizeof(ufbx_nurbs_trim_surface), UFBX_ELEMENT_NURBS_TRIM_SURFACE));
  12091. } else if (sub_type == ufbxi_Boundary) {
  12092. ufbxi_check(ufbxi_read_element(uc, node, &attrib_info, sizeof(ufbx_nurbs_trim_boundary), UFBX_ELEMENT_NURBS_TRIM_BOUNDARY));
  12093. } else if (sub_type == ufbxi_CameraStereo) {
  12094. ufbxi_check(ufbxi_read_element(uc, node, &attrib_info, sizeof(ufbx_stereo_camera), UFBX_ELEMENT_STEREO_CAMERA));
  12095. } else if (sub_type == ufbxi_CameraSwitcher) {
  12096. ufbxi_check(ufbxi_read_element(uc, node, &attrib_info, sizeof(ufbx_camera_switcher), UFBX_ELEMENT_CAMERA_SWITCHER));
  12097. } else if (sub_type == ufbxi_FKEffector) {
  12098. ufbxi_check(ufbxi_read_marker(uc, node, &attrib_info, sub_type, UFBX_MARKER_FK_EFFECTOR));
  12099. } else if (sub_type == ufbxi_IKEffector) {
  12100. ufbxi_check(ufbxi_read_marker(uc, node, &attrib_info, sub_type, UFBX_MARKER_IK_EFFECTOR));
  12101. } else if (sub_type == ufbxi_LodGroup) {
  12102. ufbxi_check(ufbxi_read_element(uc, node, &attrib_info, sizeof(ufbx_lod_group), UFBX_ELEMENT_LOD_GROUP));
  12103. } else {
  12104. ufbx_string sub_type_str = { sub_type, strlen(sub_type) };
  12105. ufbxi_check(ufbxi_read_unknown(uc, node, &attrib_info, type_str, sub_type_str, super_type));
  12106. }
  12107. ufbxi_check(ufbxi_connect_oo(uc, attrib_info.fbx_id, info->fbx_id));
  12108. return 1;
  12109. }
  12110. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_global_settings(ufbxi_context *uc, ufbxi_node *node)
  12111. {
  12112. ufbxi_check(ufbxi_read_properties(uc, node, &uc->scene.settings.props));
  12113. return 1;
  12114. }
  12115. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_object(ufbxi_context *uc, ufbxi_node *node)
  12116. {
  12117. ufbxi_element_info info = { 0 };
  12118. info.dom_node = ufbxi_get_dom_node(uc, node);
  12119. if (node->name == ufbxi_GlobalSettings) {
  12120. ufbxi_check(ufbxi_read_global_settings(uc, node));
  12121. return 1;
  12122. }
  12123. ufbx_string type_and_name, sub_type_str;
  12124. // Failing to parse the object properties is not an error since
  12125. // there's some weird objects mixed in every now and then.
  12126. // FBX version 7000 and up uses 64-bit unique IDs per object,
  12127. // older FBX versions just use name/type pairs, which we can
  12128. // use as IDs since all strings are interned into a string pool.
  12129. if (uc->version >= 7000) {
  12130. if (!ufbxi_get_val3(node, "Lss", &info.fbx_id, &type_and_name, &sub_type_str)) return 1;
  12131. ufbxi_check((info.fbx_id & UFBXI_SYNTHETIC_ID_BIT) == 0);
  12132. } else {
  12133. if (!ufbxi_get_val2(node, "ss", &type_and_name, &sub_type_str)) return 1;
  12134. info.fbx_id = ufbxi_synthetic_id_from_string(type_and_name.data);
  12135. }
  12136. // Remove the "Fbx" prefix from sub-types, remember to re-intern!
  12137. if (sub_type_str.length > 3 && !memcmp(sub_type_str.data, "Fbx", 3)) {
  12138. sub_type_str.data += 3;
  12139. sub_type_str.length -= 3;
  12140. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &sub_type_str, false));
  12141. }
  12142. ufbx_string type_str;
  12143. ufbxi_check(ufbxi_split_type_and_name(uc, type_and_name, &type_str, &info.name));
  12144. const char *name = node->name, *sub_type = sub_type_str.data;
  12145. ufbxi_check(ufbxi_read_properties(uc, node, &info.props));
  12146. info.props.defaults = ufbxi_find_template(uc, name, sub_type);
  12147. if (name == ufbxi_Model) {
  12148. if (uc->version < 7000) {
  12149. ufbxi_check(ufbxi_read_synthetic_attribute(uc, node, &info, type_str, sub_type, name));
  12150. }
  12151. ufbxi_check(ufbxi_read_model(uc, node, &info));
  12152. } else if (name == ufbxi_NodeAttribute) {
  12153. if (sub_type == ufbxi_Light) {
  12154. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_light), UFBX_ELEMENT_LIGHT));
  12155. } else if (sub_type == ufbxi_Camera) {
  12156. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_camera), UFBX_ELEMENT_CAMERA));
  12157. } else if (sub_type == ufbxi_LimbNode || sub_type == ufbxi_Limb || sub_type == ufbxi_Root) {
  12158. ufbxi_check(ufbxi_read_bone(uc, node, &info, sub_type));
  12159. } else if (sub_type == ufbxi_Null || sub_type == ufbxi_Marker) {
  12160. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_empty), UFBX_ELEMENT_EMPTY));
  12161. } else if (sub_type == ufbxi_CameraStereo) {
  12162. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_stereo_camera), UFBX_ELEMENT_STEREO_CAMERA));
  12163. } else if (sub_type == ufbxi_CameraSwitcher) {
  12164. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_camera_switcher), UFBX_ELEMENT_CAMERA_SWITCHER));
  12165. } else if (sub_type == ufbxi_FKEffector) {
  12166. ufbxi_check(ufbxi_read_marker(uc, node, &info, sub_type, UFBX_MARKER_FK_EFFECTOR));
  12167. } else if (sub_type == ufbxi_IKEffector) {
  12168. ufbxi_check(ufbxi_read_marker(uc, node, &info, sub_type, UFBX_MARKER_IK_EFFECTOR));
  12169. } else if (sub_type == ufbxi_LodGroup) {
  12170. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_lod_group), UFBX_ELEMENT_LOD_GROUP));
  12171. } else {
  12172. ufbxi_check(ufbxi_read_unknown(uc, node, &info, type_str, sub_type_str, name));
  12173. }
  12174. } else if (name == ufbxi_Geometry) {
  12175. if (sub_type == ufbxi_Mesh) {
  12176. ufbxi_check(ufbxi_read_mesh(uc, node, &info));
  12177. } else if (sub_type == ufbxi_Shape) {
  12178. ufbxi_check(ufbxi_read_shape(uc, node, &info));
  12179. } else if (sub_type == ufbxi_NurbsCurve) {
  12180. ufbxi_check(ufbxi_read_nurbs_curve(uc, node, &info));
  12181. } else if (sub_type == ufbxi_NurbsSurface) {
  12182. ufbxi_check(ufbxi_read_nurbs_surface(uc, node, &info));
  12183. } else if (sub_type == ufbxi_Line) {
  12184. ufbxi_check(ufbxi_read_line(uc, node, &info));
  12185. } else if (sub_type == ufbxi_TrimNurbsSurface) {
  12186. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_nurbs_trim_surface), UFBX_ELEMENT_NURBS_TRIM_SURFACE));
  12187. } else if (sub_type == ufbxi_Boundary) {
  12188. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_nurbs_trim_boundary), UFBX_ELEMENT_NURBS_TRIM_BOUNDARY));
  12189. } else {
  12190. ufbxi_check(ufbxi_read_unknown(uc, node, &info, type_str, sub_type_str, name));
  12191. }
  12192. } else if (name == ufbxi_Deformer) {
  12193. if (sub_type == ufbxi_Skin) {
  12194. ufbxi_check(ufbxi_read_skin(uc, node, &info));
  12195. } else if (sub_type == ufbxi_Cluster) {
  12196. ufbxi_check(ufbxi_read_skin_cluster(uc, node, &info));
  12197. } else if (sub_type == ufbxi_BlendShape) {
  12198. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_blend_deformer), UFBX_ELEMENT_BLEND_DEFORMER));
  12199. } else if (sub_type == ufbxi_BlendShapeChannel) {
  12200. ufbxi_check(ufbxi_read_blend_channel(uc, node, &info));
  12201. } else if (sub_type == ufbxi_VertexCacheDeformer) {
  12202. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_cache_deformer), UFBX_ELEMENT_CACHE_DEFORMER));
  12203. } else {
  12204. ufbxi_check(ufbxi_read_unknown(uc, node, &info, type_str, sub_type_str, name));
  12205. }
  12206. } else if (name == ufbxi_Material) {
  12207. ufbxi_check(ufbxi_read_material(uc, node, &info));
  12208. } else if (name == ufbxi_Texture) {
  12209. ufbxi_check(ufbxi_read_texture(uc, node, &info));
  12210. } else if (name == ufbxi_LayeredTexture) {
  12211. ufbxi_check(ufbxi_read_layered_texture(uc, node, &info));
  12212. } else if (name == ufbxi_Video) {
  12213. ufbxi_check(ufbxi_read_video(uc, node, &info));
  12214. } else if (name == ufbxi_AnimationStack) {
  12215. ufbxi_check(ufbxi_read_anim_stack(uc, node, &info));
  12216. } else if (name == ufbxi_AnimationLayer) {
  12217. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_anim_layer), UFBX_ELEMENT_ANIM_LAYER));
  12218. } else if (name == ufbxi_AnimationCurveNode) {
  12219. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_anim_value), UFBX_ELEMENT_ANIM_VALUE));
  12220. } else if (name == ufbxi_AnimationCurve) {
  12221. ufbxi_check(ufbxi_read_animation_curve(uc, node, &info));
  12222. } else if (name == ufbxi_Pose) {
  12223. ufbxi_check(ufbxi_read_pose(uc, node, &info, sub_type));
  12224. } else if (name == ufbxi_Implementation) {
  12225. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_shader), UFBX_ELEMENT_SHADER));
  12226. } else if (name == ufbxi_BindingTable) {
  12227. ufbxi_check(ufbxi_read_binding_table(uc, node, &info));
  12228. } else if (name == ufbxi_Collection) {
  12229. if (sub_type == ufbxi_SelectionSet) {
  12230. ufbxi_check(ufbxi_read_selection_set(uc, node, &info));
  12231. }
  12232. } else if (name == ufbxi_CollectionExclusive) {
  12233. if (sub_type == ufbxi_DisplayLayer) {
  12234. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_display_layer), UFBX_ELEMENT_DISPLAY_LAYER));
  12235. }
  12236. } else if (name == ufbxi_SelectionNode) {
  12237. ufbxi_check(ufbxi_read_selection_node(uc, node, &info));
  12238. } else if (name == ufbxi_Constraint) {
  12239. if (sub_type == ufbxi_Character) {
  12240. ufbxi_check(ufbxi_read_character(uc, node, &info));
  12241. } else {
  12242. ufbxi_check(ufbxi_read_constraint(uc, node, &info));
  12243. }
  12244. } else if (name == ufbxi_SceneInfo) {
  12245. ufbxi_check(ufbxi_read_scene_info(uc, node));
  12246. } else if (name == ufbxi_Cache) {
  12247. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_cache_file), UFBX_ELEMENT_CACHE_FILE));
  12248. } else if (name == ufbxi_ObjectMetaData) {
  12249. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_metadata_object), UFBX_ELEMENT_METADATA_OBJECT));
  12250. } else if (name == ufbxi_AudioLayer) {
  12251. ufbxi_check(ufbxi_read_element(uc, node, &info, sizeof(ufbx_audio_layer), UFBX_ELEMENT_AUDIO_LAYER));
  12252. } else if (name == ufbxi_Audio) {
  12253. ufbxi_check(ufbxi_read_audio_clip(uc, node, &info));
  12254. } else {
  12255. ufbxi_check(ufbxi_read_unknown(uc, node, &info, type_str, sub_type_str, name));
  12256. }
  12257. return 1;
  12258. }
  12259. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_objects(ufbxi_context *uc)
  12260. {
  12261. for (;;) {
  12262. // Push a deferred element ID for tagging warnings
  12263. uc->p_element_id = ufbxi_push(&uc->tmp_element_id, uint32_t, 1);
  12264. ufbxi_check(uc->p_element_id);
  12265. *uc->p_element_id = UFBX_NO_INDEX;
  12266. uc->warnings.deferred_element_id_plus_one = (uint32_t)uc->tmp_element_id.num_items;
  12267. ufbxi_node *node;
  12268. ufbxi_check(ufbxi_parse_toplevel_child(uc, &node, NULL));
  12269. if (!node) break;
  12270. ufbxi_check(ufbxi_read_object(uc, node));
  12271. uc->warnings.deferred_element_id_plus_one = 0;
  12272. uc->p_element_id = NULL;
  12273. }
  12274. return 1;
  12275. }
  12276. typedef struct {
  12277. ufbxi_node **nodes;
  12278. size_t num_nodes;
  12279. uint32_t task_index;
  12280. } ufbxi_object_batch;
  12281. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_objects_threaded(ufbxi_context *uc)
  12282. {
  12283. uc->parse_threaded = true;
  12284. bool parsed_to_end = false;
  12285. ufbxi_object_batch batches[UFBX_THREAD_GROUP_COUNT]; // ufbxi_uninit
  12286. memset(batches, 0, sizeof(batches));
  12287. size_t empty_count = 0;
  12288. size_t batch_index = 0;
  12289. while (empty_count < UFBX_THREAD_GROUP_COUNT) {
  12290. ufbxi_object_batch *batch = &batches[batch_index];
  12291. ufbxi_check(ufbxi_thread_pool_wait_group(&uc->thread_pool));
  12292. if (batch->num_nodes > 0) {
  12293. ufbxi_for_ptr(ufbxi_node, p_node, batch->nodes, batch->num_nodes) {
  12294. ufbxi_buf_clear(&uc->tmp_parse);
  12295. // Push a deferred element ID for tagging warnings
  12296. uc->p_element_id = ufbxi_push(&uc->tmp_element_id, uint32_t, 1);
  12297. ufbxi_check(uc->p_element_id);
  12298. *uc->p_element_id = UFBX_NO_INDEX;
  12299. uc->warnings.deferred_element_id_plus_one = (uint32_t)uc->tmp_element_id.num_items;
  12300. ufbxi_check(ufbxi_read_object(uc, *p_node));
  12301. uc->warnings.deferred_element_id_plus_one = 0;
  12302. uc->p_element_id = NULL;
  12303. }
  12304. batch->num_nodes = 0;
  12305. }
  12306. ufbxi_buf *tmp_buf = &uc->tmp_thread_parse[batch_index];
  12307. // ASCII data may be in `tmp_buf`, so copy it to safety in case
  12308. if (uc->ascii.src_buf == tmp_buf) {
  12309. ufbxi_ascii *ua = &uc->ascii;
  12310. size_t size = ufbxi_to_size(ua->src_end - ua->src);
  12311. if (uc->read_buffer_size < size) {
  12312. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->read_buffer, &uc->read_buffer_size, size));
  12313. }
  12314. memcpy(uc->read_buffer, ua->src, size);
  12315. uc->data = uc->data_begin = ua->src = uc->read_buffer;
  12316. ua->src_end = uc->read_buffer + size;
  12317. ua->src_is_retained = false;
  12318. ua->src_buf = NULL;
  12319. if (ufbxi_to_size(ua->src_end - ua->src) < uc->progress_interval) {
  12320. ua->src_yield = ua->src_end;
  12321. } else {
  12322. ua->src_yield = ua->src + uc->progress_interval;
  12323. }
  12324. uc->data = ua->src;
  12325. }
  12326. ufbxi_buf_clear(tmp_buf);
  12327. if (!parsed_to_end) {
  12328. size_t num_nodes = 0;
  12329. uint32_t task_start = uc->thread_pool.start_index;
  12330. uint32_t max_tasks = uc->thread_pool.num_tasks / UFBX_THREAD_GROUP_COUNT;
  12331. max_tasks = ufbxi_min32(max_tasks, ufbxi_thread_pool_available_tasks(&uc->thread_pool));
  12332. size_t max_memory = uc->opts.thread_opts.memory_limit / UFBX_THREAD_GROUP_COUNT;
  12333. for (;;) {
  12334. ufbxi_node *node = NULL;
  12335. ufbxi_check(ufbxi_parse_toplevel_child(uc, &node, tmp_buf));
  12336. if (!node) {
  12337. parsed_to_end = true;
  12338. break;
  12339. }
  12340. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbxi_node*, 1, &node));
  12341. num_nodes++;
  12342. uint32_t num_tasks = uc->thread_pool.start_index - task_start;
  12343. if (num_tasks >= max_tasks) break;
  12344. size_t memory_used = tmp_buf->pushed_size + tmp_buf->pos;
  12345. if (memory_used >= max_memory) break;
  12346. }
  12347. batch->num_nodes = num_nodes;
  12348. batch->nodes = ufbxi_push_pop(tmp_buf, &uc->tmp_stack, ufbxi_node*, num_nodes);
  12349. ufbxi_check(batch->nodes);
  12350. batch->task_index = uc->thread_pool.start_index;
  12351. }
  12352. // Not safe to refer to this buffer anymore
  12353. uc->ascii.src_is_retained = false;
  12354. ufbxi_thread_pool_flush_group(&uc->thread_pool);
  12355. if (batch->num_nodes == 0) {
  12356. empty_count += 1;
  12357. }
  12358. batch_index = (batch_index + 1) % UFBX_THREAD_GROUP_COUNT;
  12359. }
  12360. ufbxi_check(ufbxi_thread_pool_wait_all(&uc->thread_pool));
  12361. uc->parse_threaded = false;
  12362. return 1;
  12363. }
  12364. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_connections(ufbxi_context *uc)
  12365. {
  12366. // Read the connections to the list first
  12367. for (;;) {
  12368. ufbxi_node *node;
  12369. ufbxi_check(ufbxi_parse_toplevel_child(uc, &node, NULL));
  12370. if (!node) break;
  12371. char *type;
  12372. uint64_t src_id = 0, dst_id = 0;
  12373. ufbx_string src_prop = ufbx_empty_string, dst_prop = ufbx_empty_string;
  12374. if (uc->version < 7000) {
  12375. char *src_name = NULL, *dst_name = NULL;
  12376. // Pre-7000 versions use Type::Name pairs as identifiers
  12377. if (!ufbxi_get_val1(node, "c", &type)) continue;
  12378. if (type == ufbxi_OO) {
  12379. if (!ufbxi_get_val3(node, "_cc", NULL, &src_name, &dst_name)) continue;
  12380. } else if (type == ufbxi_OP) {
  12381. if (!ufbxi_get_val4(node, "_ccs", NULL, &src_name, &dst_name, &dst_prop)) continue;
  12382. } else if (type == ufbxi_PO) {
  12383. if (!ufbxi_get_val4(node, "_csc", NULL, &src_name, &src_prop, &dst_name)) continue;
  12384. } else if (type == ufbxi_PP) {
  12385. if (!ufbxi_get_val5(node, "_cscs", NULL, &src_name, &src_prop, &dst_name, &dst_prop)) continue;
  12386. } else {
  12387. // TODO: Strict mode?
  12388. continue;
  12389. }
  12390. if (src_prop.length > 0) {
  12391. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &src_prop, false));
  12392. }
  12393. if (dst_prop.length > 0) {
  12394. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &dst_prop, false));
  12395. }
  12396. src_id = ufbxi_synthetic_id_from_string(src_name);
  12397. dst_id = ufbxi_synthetic_id_from_string(dst_name);
  12398. } else {
  12399. // Post-7000 versions use proper unique 64-bit IDs
  12400. if (!ufbxi_get_val1(node, "C", &type)) continue;
  12401. if (type == ufbxi_OO) {
  12402. if (!ufbxi_get_val3(node, "_LL", NULL, &src_id, &dst_id)) continue;
  12403. } else if (type == ufbxi_OP) {
  12404. if (!ufbxi_get_val4(node, "_LLS", NULL, &src_id, &dst_id, &dst_prop)) continue;
  12405. } else if (type == ufbxi_PO) {
  12406. if (!ufbxi_get_val4(node, "_LSL", NULL, &src_id, &src_prop, &dst_id)) continue;
  12407. } else if (type == ufbxi_PP) {
  12408. if (!ufbxi_get_val5(node, "_LSLS", NULL, &src_id, &src_prop, &dst_id, &dst_prop)) continue;
  12409. } else {
  12410. // TODO: Strict mode?
  12411. continue;
  12412. }
  12413. }
  12414. ufbxi_tmp_connection *conn = ufbxi_push(&uc->tmp_connections, ufbxi_tmp_connection, 1);
  12415. ufbxi_check(conn);
  12416. conn->src = src_id;
  12417. conn->dst = dst_id;
  12418. conn->src_prop = src_prop;
  12419. conn->dst_prop = dst_prop;
  12420. }
  12421. return 1;
  12422. }
  12423. // -- Pre-7000 "Take" based animation
  12424. ufbxi_forceinline static char ufbxi_double_to_char(double value)
  12425. {
  12426. if (value >= 0.0 && value <= 127.0) {
  12427. return (char)(int)value;
  12428. } else {
  12429. return 0;
  12430. }
  12431. }
  12432. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_take_anim_channel(ufbxi_context *uc, ufbxi_node *node, uint64_t value_fbx_id, const char *name, ufbx_real *p_default)
  12433. {
  12434. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_Default, "R", p_default));
  12435. // Find the key array, early return with success if not found as we may have only a default
  12436. ufbxi_value_array *keys = ufbxi_find_array(node, ufbxi_Key, 'd');
  12437. if (!keys) return 1;
  12438. uint64_t curve_fbx_id = 0;
  12439. ufbx_anim_curve *curve = ufbxi_push_synthetic_element(uc, &curve_fbx_id, node, name, ufbx_anim_curve, UFBX_ELEMENT_ANIM_CURVE);
  12440. ufbxi_check(curve);
  12441. ufbxi_check(ufbxi_connect_op(uc, curve_fbx_id, value_fbx_id, curve->name));
  12442. if (uc->opts.ignore_animation) return 1;
  12443. size_t num_keys = 0;
  12444. ufbxi_check(ufbxi_find_val1(node, ufbxi_KeyCount, "Z", &num_keys));
  12445. curve->keyframes.data = ufbxi_push(&uc->result, ufbx_keyframe, num_keys);
  12446. curve->keyframes.count = num_keys;
  12447. ufbxi_check(curve->keyframes.data);
  12448. float slope_left = 0.0f;
  12449. float weight_left = 0.333333f;
  12450. double next_time = 0.0;
  12451. double next_value = 0.0;
  12452. double prev_time = 0.0;
  12453. // The pre-7000 keyframe data is stored as a _heterogenous_ array containing 64-bit integers,
  12454. // floating point values, and _bare characters_. We cast all values to double and interpret them.
  12455. double *data = (double*)keys->data, *data_end = data + keys->size;
  12456. if (num_keys > 0) {
  12457. ufbxi_check(data_end - data >= 2);
  12458. next_time = data[0] / uc->ktime_sec_double;
  12459. next_value = data[1];
  12460. }
  12461. for (size_t i = 0; i < num_keys; i++) {
  12462. ufbx_keyframe *key = &curve->keyframes.data[i];
  12463. if (i == 0) {
  12464. curve->min_value = (ufbx_real)next_value;
  12465. curve->max_value = (ufbx_real)next_value;
  12466. } else {
  12467. curve->min_value = ufbxi_min_real(curve->min_value, (ufbx_real)next_value);
  12468. curve->max_value = ufbxi_max_real(curve->max_value, (ufbx_real)next_value);
  12469. }
  12470. // First three values: Time, Value, InterpolationMode
  12471. ufbxi_check(data_end - data >= 3);
  12472. key->time = next_time;
  12473. key->value = (ufbx_real)next_value;
  12474. char mode = ufbxi_double_to_char(data[2]);
  12475. data += 3;
  12476. float slope_right = 0.0f;
  12477. float weight_right = 0.333333f;
  12478. float next_slope_left = 0.0f;
  12479. float next_weight_left = 0.333333f;
  12480. bool auto_slope = false;
  12481. if (mode == 'U') {
  12482. // Cubic interpolation
  12483. key->interpolation = UFBX_INTERPOLATION_CUBIC;
  12484. ufbxi_check(data_end - data >= 1);
  12485. char slope_mode = ufbxi_double_to_char(data[0]);
  12486. data += 1;
  12487. size_t num_weights = 1;
  12488. if (slope_mode == 's' || slope_mode == 'b') {
  12489. // Slope mode 's'/'b' (standard? broken?) always have two explicit slopes
  12490. // TODO: `b` might actually be some kind of TCB curve
  12491. ufbxi_check(data_end - data >= 2);
  12492. slope_right = (float)data[0];
  12493. next_slope_left = (float)data[1];
  12494. data += 2;
  12495. } else if (slope_mode == 'a') {
  12496. // Parameterless slope mode 'a' seems to appear in baked animations. Let's just assume
  12497. // automatic tangents for now as they're the least likely to break with
  12498. // objectionable artifacts. We need to defer the automatic tangent resolve
  12499. // until we have read the next time/value.
  12500. // TODO: Solve what this is more throroughly
  12501. auto_slope = true;
  12502. if (uc->version == 5000) {
  12503. num_weights = 0;
  12504. }
  12505. } else if (slope_mode == 'p') {
  12506. // TODO: What is this mode? It seems to have negative values sometimes?
  12507. // Also it seems to have _two_ trailing weights values, currently observed:
  12508. // `n,n` and `a,X,Y,n`...
  12509. // Ignore unknown values for now
  12510. ufbxi_check(data_end - data >= 2);
  12511. data += 2;
  12512. num_weights = 2;
  12513. } else if (slope_mode == 't') {
  12514. // TODO: What is this mode? It seems that it does not have any weights and the
  12515. // third value seems _tiny_ (around 1e-30?)
  12516. ufbxi_check(data_end - data >= 3);
  12517. data += 3;
  12518. num_weights = 0;
  12519. } else {
  12520. ufbxi_fail("Unknown slope mode");
  12521. }
  12522. for (; num_weights > 0; num_weights--) {
  12523. ufbxi_check(data_end - data >= 1);
  12524. char weight_mode = ufbxi_double_to_char(data[0]);
  12525. data += 1;
  12526. if (weight_mode == 'n') {
  12527. // Automatic weights (0.3333...)
  12528. } else if (weight_mode == 'a') {
  12529. // Manual weights: RightWeight, NextLeftWeight
  12530. ufbxi_check(data_end - data >= 2);
  12531. weight_right = (float)data[0];
  12532. next_weight_left = (float)data[1];
  12533. data += 2;
  12534. } else if (weight_mode == 'l') {
  12535. // Next left tangent is weighted
  12536. ufbxi_check(data_end - data >= 1);
  12537. next_weight_left = (float)data[0];
  12538. data += 1;
  12539. } else if (weight_mode == 'r') {
  12540. // Right tangent is weighted
  12541. ufbxi_check(data_end - data >= 1);
  12542. weight_right = (float)data[0];
  12543. data += 1;
  12544. } else if (weight_mode == 'c') {
  12545. // TODO: What is this mode? At least it has no parameters so let's
  12546. // just assume automatic weights for the time being (0.3333...)
  12547. } else {
  12548. ufbxi_fail("Unknown weight mode");
  12549. }
  12550. }
  12551. } else if (mode == 'L') {
  12552. // Linear interpolation: No parameters
  12553. key->interpolation = UFBX_INTERPOLATION_LINEAR;
  12554. } else if (mode == 'C') {
  12555. // Constant interpolation: Single parameter (use prev/next)
  12556. ufbxi_check(data_end - data >= 1);
  12557. key->interpolation = ufbxi_double_to_char(data[0]) == 'n' ? UFBX_INTERPOLATION_CONSTANT_NEXT : UFBX_INTERPOLATION_CONSTANT_PREV;
  12558. data += 1;
  12559. } else {
  12560. ufbxi_fail("Unknown key mode");
  12561. }
  12562. // Retrieve next key and value
  12563. if (i + 1 < num_keys) {
  12564. ufbxi_check(data_end - data >= 2);
  12565. next_time = data[0] / uc->ktime_sec_double;
  12566. next_value = data[1];
  12567. }
  12568. if (auto_slope) {
  12569. if (i > 0) {
  12570. slope_left = slope_right = ufbxi_solve_auto_tangent(uc,
  12571. prev_time, key->time, next_time,
  12572. key[-1].value, key->value, (ufbx_real)next_value,
  12573. weight_left, weight_right, 0.0f, UFBXI_KEY_CLAMP_PROGRESSIVE|UFBXI_KEY_TIME_INDEPENDENT);
  12574. } else {
  12575. slope_left = slope_right = 0.0f;
  12576. }
  12577. }
  12578. // Set up linear cubic tangents if necessary
  12579. if (key->interpolation == UFBX_INTERPOLATION_LINEAR) {
  12580. if (next_time > key->time) {
  12581. double slope = (next_value - key->value) / (next_time - key->time);
  12582. slope_right = next_slope_left = (float)slope;
  12583. } else {
  12584. slope_right = next_slope_left = 0.0f;
  12585. }
  12586. }
  12587. if (key->time > prev_time) {
  12588. double delta = key->time - prev_time;
  12589. key->left.dx = (float)(weight_left * delta);
  12590. key->left.dy = key->left.dx * slope_left;
  12591. } else {
  12592. key->left.dx = 0.0f;
  12593. key->left.dy = 0.0f;
  12594. }
  12595. if (next_time > key->time) {
  12596. double delta = next_time - key->time;
  12597. key->right.dx = (float)(weight_right * delta);
  12598. key->right.dy = key->right.dx * slope_right;
  12599. } else {
  12600. key->right.dx = 0.0f;
  12601. key->right.dy = 0.0f;
  12602. }
  12603. slope_left = next_slope_left;
  12604. weight_left = next_weight_left;
  12605. prev_time = key->time;
  12606. }
  12607. ufbxi_check(data == data_end);
  12608. return 1;
  12609. }
  12610. // Recursion limited as it is further called only for `name="T"/"R"/"S"` and
  12611. // cannot enter the `name=="Transform"` branch.
  12612. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_take_prop_channel(ufbxi_context *uc, ufbxi_node *node, uint64_t target_fbx_id, uint64_t layer_fbx_id, ufbx_string name)
  12613. ufbxi_recursive_function(int, ufbxi_read_take_prop_channel, (uc, node, target_fbx_id, layer_fbx_id, name), 2,
  12614. (ufbxi_context *uc, ufbxi_node *node, uint64_t target_fbx_id, uint64_t layer_fbx_id, ufbx_string name))
  12615. {
  12616. if (name.data == ufbxi_Transform) {
  12617. // Pre-7000 have transform keyframes in a deeply nested structure,
  12618. // flatten it to make it resemble post-7000 structure a bit closer:
  12619. // old: Model: { Channel: "Transform" { Channel: "T" { Channel "X": { ... } } } }
  12620. // new: Model: { Channel: "Lcl Translation" { Channel "X": { ... } } }
  12621. ufbxi_for(ufbxi_node, child, node->children, node->num_children) {
  12622. if (child->name != ufbxi_Channel) continue;
  12623. const char *old_name = NULL;
  12624. ufbxi_check(ufbxi_get_val1(child, "C", (char**)&old_name));
  12625. ufbx_string new_name;
  12626. if (old_name == ufbxi_T) { new_name.data = ufbxi_Lcl_Translation; new_name.length = sizeof(ufbxi_Lcl_Translation) - 1; }
  12627. else if (old_name == ufbxi_R) { new_name.data = ufbxi_Lcl_Rotation; new_name.length = sizeof(ufbxi_Lcl_Rotation) - 1; }
  12628. else if (old_name == ufbxi_S) { new_name.data = ufbxi_Lcl_Scaling; new_name.length = sizeof(ufbxi_Lcl_Scaling) - 1; }
  12629. else {
  12630. continue;
  12631. }
  12632. // Read child as a top-level property channel
  12633. ufbxi_check(ufbxi_read_take_prop_channel(uc, child, target_fbx_id, layer_fbx_id, new_name));
  12634. }
  12635. } else {
  12636. // Pre-6000 FBX files store blend shape keys with a " (Shape)" suffix
  12637. if (uc->version < 6000) {
  12638. const char *const suffix = " (Shape)";
  12639. size_t suffix_len = strlen(suffix);
  12640. if (name.length > suffix_len && !memcmp(name.data + name.length - suffix_len, suffix, suffix_len)) {
  12641. name.length -= suffix_len;
  12642. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &name, false));
  12643. }
  12644. }
  12645. // Find 1-3 channel nodes that contain a `Key:` node
  12646. ufbxi_node *channel_nodes[3] = { 0 };
  12647. const char *channel_names[3] = { 0 };
  12648. size_t num_channel_nodes = 0;
  12649. if (ufbxi_find_child(node, ufbxi_Key) || ufbxi_find_child(node, ufbxi_Default)) {
  12650. // Channel has only a single curve
  12651. channel_nodes[0] = node;
  12652. channel_names[0] = name.data;
  12653. num_channel_nodes = 1;
  12654. } else {
  12655. // Channel is a compound of multiple curves
  12656. ufbxi_for(ufbxi_node, child, node->children, node->num_children) {
  12657. if (child->name != ufbxi_Channel) continue;
  12658. if (!ufbxi_find_child(child, ufbxi_Key) && !ufbxi_find_child(child, ufbxi_Default)) continue;
  12659. if (!ufbxi_get_val1(child, "C", (char**)&channel_names[num_channel_nodes])) continue;
  12660. channel_nodes[num_channel_nodes] = child;
  12661. if (++num_channel_nodes == 3) break;
  12662. }
  12663. }
  12664. // Early return: No valid channels found, not an error
  12665. if (num_channel_nodes == 0) return 1;
  12666. uint64_t value_fbx_id = 0;
  12667. ufbx_anim_value *value = ufbxi_push_synthetic_element(uc, &value_fbx_id, node, name.data, ufbx_anim_value, UFBX_ELEMENT_ANIM_VALUE);
  12668. // Add a "virtual" connection between the animated property and the layer/target
  12669. ufbxi_check(ufbxi_connect_oo(uc, value_fbx_id, layer_fbx_id));
  12670. ufbxi_check(ufbxi_connect_op(uc, value_fbx_id, target_fbx_id, name));
  12671. for (size_t i = 0; i < num_channel_nodes; i++) {
  12672. ufbxi_check(ufbxi_read_take_anim_channel(uc, channel_nodes[i], value_fbx_id, channel_names[i], &value->default_value.v[i]));
  12673. }
  12674. }
  12675. return 1;
  12676. }
  12677. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_take_object(ufbxi_context *uc, ufbxi_node *node, uint64_t layer_fbx_id)
  12678. {
  12679. // Takes are used only in pre-7000 FBX versions so objects are identified
  12680. // by their unique Type::Name pair that we use as unique IDs through the
  12681. // pooled interned string pointers.
  12682. const char *type_and_name = NULL;
  12683. ufbxi_check(ufbxi_get_val1(node, "c", (char**)&type_and_name));
  12684. uint64_t target_fbx_id = ufbxi_synthetic_id_from_string(type_and_name);
  12685. // Add all suitable Channels as animated properties
  12686. ufbxi_for(ufbxi_node, child, node->children, node->num_children) {
  12687. ufbx_string name;
  12688. if (child->name != ufbxi_Channel) continue;
  12689. if (!ufbxi_get_val1(child, "S", &name)) continue;
  12690. ufbxi_check(ufbxi_read_take_prop_channel(uc, child, target_fbx_id, layer_fbx_id, name));
  12691. }
  12692. return 1;
  12693. }
  12694. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_take(ufbxi_context *uc, ufbxi_node *node)
  12695. {
  12696. ufbx_prop tmp_props[4];
  12697. uint32_t num_props = 0;
  12698. memset(tmp_props, 0, sizeof(tmp_props));
  12699. int64_t start = 0, stop = 0;
  12700. if (ufbxi_find_val2(node, ufbxi_LocalTime, "LL", &start, &stop)) {
  12701. ufbxi_init_synthetic_int_prop(&tmp_props[num_props++], ufbxi_LocalStart, start, UFBX_PROP_INTEGER);
  12702. ufbxi_init_synthetic_int_prop(&tmp_props[num_props++], ufbxi_LocalStop, stop, UFBX_PROP_INTEGER);
  12703. }
  12704. if (ufbxi_find_val2(node, ufbxi_ReferenceTime, "LL", &start, &stop)) {
  12705. ufbxi_init_synthetic_int_prop(&tmp_props[num_props++], ufbxi_ReferenceStart, start, UFBX_PROP_INTEGER);
  12706. ufbxi_init_synthetic_int_prop(&tmp_props[num_props++], ufbxi_ReferenceStop, stop, UFBX_PROP_INTEGER);
  12707. }
  12708. const char *name;
  12709. ufbxi_check(ufbxi_get_val1(node, "C", (char**)&name));
  12710. // Hack: For post-7000 files we are only interested in the animation times
  12711. // for fallback in case the information is missing in the stacks.
  12712. if (uc->version >= 7000) {
  12713. uint32_t hash = ufbxi_hash_ptr(name);
  12714. ufbxi_tmp_anim_stack *entry = ufbxi_map_find(&uc->anim_stack_map, ufbxi_tmp_anim_stack, hash, &name);
  12715. if (entry) {
  12716. ufbx_anim_stack *stack = entry->stack;
  12717. if (stack->props.props.count == 0) {
  12718. stack->props.props.count = num_props;
  12719. stack->props.props.data = ufbxi_push_copy(&uc->result, ufbx_prop, num_props, tmp_props);
  12720. ufbxi_check(stack->props.props.data);
  12721. }
  12722. }
  12723. return 1;
  12724. }
  12725. uint64_t stack_fbx_id = 0, layer_fbx_id = 0;
  12726. // Treat the Take as a post-7000 version animation stack and layer.
  12727. ufbx_anim_stack *stack = ufbxi_push_synthetic_element(uc, &stack_fbx_id, node, name, ufbx_anim_stack, UFBX_ELEMENT_ANIM_STACK);
  12728. ufbxi_check(stack);
  12729. stack->props.props.count = num_props;
  12730. stack->props.props.data = ufbxi_push_copy(&uc->result, ufbx_prop, num_props, tmp_props);
  12731. ufbxi_check(stack->props.props.data);
  12732. ufbx_anim_layer *layer = ufbxi_push_synthetic_element(uc, &layer_fbx_id, node, ufbxi_BaseLayer, ufbx_anim_layer, UFBX_ELEMENT_ANIM_LAYER);
  12733. ufbxi_check(layer);
  12734. ufbxi_check(ufbxi_connect_oo(uc, layer_fbx_id, stack_fbx_id));
  12735. // Read all properties of objects included in the take
  12736. ufbxi_for(ufbxi_node, child, node->children, node->num_children) {
  12737. // TODO: Do some object types have another name?
  12738. if (child->name != ufbxi_Model) continue;
  12739. ufbxi_check(ufbxi_read_take_object(uc, child, layer_fbx_id));
  12740. }
  12741. return 1;
  12742. }
  12743. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_takes(ufbxi_context *uc)
  12744. {
  12745. for (;;) {
  12746. ufbxi_node *node;
  12747. ufbxi_check(ufbxi_parse_toplevel_child(uc, &node, NULL));
  12748. if (!node) break;
  12749. if (node->name == ufbxi_Take) {
  12750. ufbxi_check(ufbxi_read_take(uc, node));
  12751. }
  12752. }
  12753. return 1;
  12754. }
  12755. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_settings(ufbxi_context *uc, ufbxi_node *node)
  12756. {
  12757. if (uc->read_legacy_settings) return 1;
  12758. uc->read_legacy_settings = true;
  12759. ufbx_prop tmp_props[2];
  12760. uint32_t num_props = 0;
  12761. memset(tmp_props, 0, sizeof(tmp_props));
  12762. ufbxi_node *frame_rate = ufbxi_find_child_strcmp(node, "FrameRate");
  12763. if (frame_rate) {
  12764. double fps = 0.0;
  12765. if (!ufbxi_get_val1(frame_rate, "D", &fps)) {
  12766. ufbx_string str;
  12767. if (ufbxi_get_val1(frame_rate, "S", &str)) {
  12768. char *end;
  12769. double val = ufbxi_parse_double(str.data, str.length, &end, uc->double_parse_flags);
  12770. if (end == str.data + str.length) {
  12771. fps = val;
  12772. }
  12773. }
  12774. }
  12775. if (fps > 0.0) {
  12776. ufbxi_init_synthetic_real_prop(&tmp_props[num_props++], ufbxi_CustomFrameRate, (ufbx_real)fps, UFBX_PROP_NUMBER);
  12777. ufbxi_init_synthetic_real_prop(&tmp_props[num_props++], ufbxi_TimeMode, UFBX_TIME_MODE_CUSTOM, UFBX_PROP_INTEGER);
  12778. }
  12779. }
  12780. if (num_props > 0) {
  12781. ufbx_props *props = &uc->scene.settings.props;
  12782. size_t num_existing = props->props.count;
  12783. size_t new_count = num_props + num_existing;
  12784. ufbx_prop *new_props = ufbxi_push(&uc->result, ufbx_prop, new_count);
  12785. ufbxi_check(new_props);
  12786. memcpy(new_props, tmp_props, num_props * sizeof(ufbx_prop));
  12787. if (num_existing > 0) {
  12788. memcpy(new_props + num_props, props->props.data, num_existing * sizeof(ufbx_prop));
  12789. }
  12790. ufbxi_check(ufbxi_sort_properties(uc, new_props, new_count));
  12791. props->props.data = new_props;
  12792. props->props.count = new_count;
  12793. ufbxi_deduplicate_properties(&props->props);
  12794. ufbxi_check(uc->scene.settings.props.props.data);
  12795. }
  12796. return 1;
  12797. }
  12798. ufbxi_noinline static ufbx_matrix ufbxi_unscaled_transform_to_matrix(const ufbx_transform *t)
  12799. {
  12800. ufbx_transform transform = *t;
  12801. transform.scale.x = 1.0f;
  12802. transform.scale.y = 1.0f;
  12803. transform.scale.z = 1.0f;
  12804. return ufbx_transform_to_matrix(&transform);
  12805. }
  12806. ufbxi_noinline static void ufbxi_setup_root_node(ufbxi_context *uc, ufbx_node *root)
  12807. {
  12808. if (uc->opts.use_root_transform) {
  12809. root->local_transform = uc->opts.root_transform;
  12810. root->node_to_parent = ufbx_transform_to_matrix(&uc->opts.root_transform);
  12811. } else {
  12812. root->local_transform = ufbx_identity_transform;
  12813. root->node_to_parent = ufbx_identity_matrix;
  12814. }
  12815. root->is_root = true;
  12816. }
  12817. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_root(ufbxi_context *uc)
  12818. {
  12819. // FBXHeaderExtension: Some metadata (optional)
  12820. ufbxi_check(ufbxi_parse_toplevel(uc, ufbxi_FBXHeaderExtension));
  12821. ufbxi_check(ufbxi_read_header_extension(uc));
  12822. // The ASCII exporter version is stored in top-level
  12823. if (uc->exporter == UFBX_EXPORTER_BLENDER_ASCII) {
  12824. ufbxi_check(ufbxi_parse_toplevel(uc, ufbxi_Creator));
  12825. if (uc->top_node) {
  12826. ufbxi_ignore(ufbxi_get_val1(uc->top_node, "S", &uc->scene.metadata.creator));
  12827. }
  12828. }
  12829. // Resolve the exporter before continuing
  12830. ufbxi_check(ufbxi_match_exporter(uc));
  12831. if (uc->version < 7000) {
  12832. ufbxi_check(ufbxi_init_node_prop_names(uc));
  12833. }
  12834. // Don't allow changing version from this point onwards
  12835. uc->ascii.found_version = true;
  12836. // Document: Read root ID
  12837. if (uc->version >= 7000) {
  12838. ufbxi_check(ufbxi_parse_toplevel(uc, ufbxi_Documents));
  12839. ufbxi_check(ufbxi_read_document(uc));
  12840. } else {
  12841. // Pre-7000: Root node has a specific type-name pair "Model::Scene"
  12842. // (or reversed in binary). Use the interned name as ID as usual.
  12843. const char *root_name = uc->from_ascii ? "Model::Scene" : "Scene\x00\x01Model";
  12844. root_name = ufbxi_push_string_imp(&uc->string_pool, root_name, 12, NULL, false, true);
  12845. ufbxi_check(root_name);
  12846. uc->root_id = ufbxi_synthetic_id_from_string(root_name);
  12847. }
  12848. // Add a nameless root node with the root ID
  12849. {
  12850. ufbxi_element_info root_info = { uc->root_id };
  12851. root_info.name = ufbx_empty_string;
  12852. ufbx_node *root = ufbxi_push_element(uc, &root_info, ufbx_node, UFBX_ELEMENT_NODE);
  12853. ufbxi_check(root);
  12854. ufbxi_setup_root_node(uc, root);
  12855. ufbxi_check(ufbxi_push_copy(&uc->tmp_node_ids, uint32_t, 1, &root->element.element_id));
  12856. }
  12857. // Definitions: Object type counts and property templates (optional)
  12858. ufbxi_check(ufbxi_parse_toplevel(uc, ufbxi_Definitions));
  12859. ufbxi_check(ufbxi_read_definitions(uc));
  12860. // Objects: Actual scene data
  12861. ufbxi_check(ufbxi_parse_toplevel(uc, ufbxi_Objects));
  12862. if (!uc->sure_fbx) {
  12863. // If the file is a bit iffy about being a real FBX file reject it if
  12864. // even the objects are not found.
  12865. ufbxi_check_msg(uc->top_node, "Not an FBX file");
  12866. }
  12867. if (uc->thread_pool.enabled) {
  12868. ufbxi_check(ufbxi_read_objects_threaded(uc));
  12869. } else {
  12870. ufbxi_check(ufbxi_read_objects(uc));
  12871. }
  12872. // Connections: Relationships between nodes
  12873. ufbxi_check(ufbxi_parse_toplevel(uc, ufbxi_Connections));
  12874. ufbxi_check(ufbxi_read_connections(uc));
  12875. // Takes: Pre-7000 animation data
  12876. ufbxi_check(ufbxi_parse_toplevel(uc, ufbxi_Takes));
  12877. ufbxi_check(ufbxi_read_takes(uc));
  12878. // Check if there's a top-level GlobalSettings that we skimmed over
  12879. ufbxi_check(ufbxi_parse_toplevel(uc, ufbxi_GlobalSettings));
  12880. if (uc->top_node) {
  12881. ufbxi_check(ufbxi_read_global_settings(uc, uc->top_node));
  12882. }
  12883. // Version5: Pre-6000 settings
  12884. ufbxi_check(ufbxi_parse_toplevel(uc, ufbxi_Version5));
  12885. if (uc->top_node) {
  12886. ufbxi_node *settings = ufbxi_find_child_strcmp(uc->top_node, "Settings");
  12887. if (settings) {
  12888. ufbxi_check(ufbxi_read_legacy_settings(uc, settings));
  12889. }
  12890. }
  12891. // Force parsing all the nodes by parsing a toplevel that cannot be found
  12892. if (uc->opts.retain_dom) {
  12893. ufbxi_check(ufbxi_parse_toplevel(uc, NULL));
  12894. }
  12895. return 1;
  12896. }
  12897. typedef struct {
  12898. const char *prop_name;
  12899. ufbx_prop_type prop_type;
  12900. const char *node_name;
  12901. const char *node_fmt;
  12902. } ufbxi_legacy_prop;
  12903. // Must be alphabetically sorted!
  12904. static const ufbxi_legacy_prop ufbxi_legacy_light_props[] = {
  12905. { ufbxi_CastLight, UFBX_PROP_BOOLEAN, ufbxi_CastLight, "L" },
  12906. { ufbxi_CastShadows, UFBX_PROP_BOOLEAN, ufbxi_CastShadows, "L" },
  12907. { ufbxi_Color, UFBX_PROP_COLOR, ufbxi_Color, "RRR" },
  12908. { ufbxi_ConeAngle, UFBX_PROP_NUMBER, ufbxi_ConeAngle, "R" },
  12909. { ufbxi_HotSpot, UFBX_PROP_NUMBER, ufbxi_HotSpot, "R" },
  12910. { ufbxi_Intensity, UFBX_PROP_NUMBER, ufbxi_Intensity, "R" },
  12911. { ufbxi_LightType, UFBX_PROP_INTEGER, ufbxi_LightType, "L" },
  12912. };
  12913. // Must be alphabetically sorted!
  12914. static const ufbxi_legacy_prop ufbxi_legacy_camera_props[] = {
  12915. { ufbxi_ApertureMode, UFBX_PROP_INTEGER, ufbxi_ApertureMode, "L" },
  12916. { ufbxi_AspectH, UFBX_PROP_NUMBER, ufbxi_AspectH, "R" },
  12917. { ufbxi_AspectRatioMode, UFBX_PROP_INTEGER, "AspectType", "L" },
  12918. { ufbxi_AspectW, UFBX_PROP_NUMBER, ufbxi_AspectW, "R" },
  12919. { ufbxi_FieldOfView, UFBX_PROP_NUMBER, "Aperture", "R" },
  12920. { ufbxi_FieldOfViewX, UFBX_PROP_NUMBER, "FieldOfViewXProperty", "R" },
  12921. { ufbxi_FieldOfViewY, UFBX_PROP_NUMBER, "FieldOfViewYProperty", "R" },
  12922. { ufbxi_FilmHeight, UFBX_PROP_NUMBER, "CameraAperture", "_R" },
  12923. { ufbxi_FilmSqueezeRatio, UFBX_PROP_NUMBER, "SqueezeRatio", "R" },
  12924. { ufbxi_FilmWidth, UFBX_PROP_NUMBER, "CameraAperture", "R_" },
  12925. { ufbxi_FocalLength, UFBX_PROP_NUMBER, ufbxi_FocalLength, "R" },
  12926. };
  12927. // Must be alphabetically sorted!
  12928. static const ufbxi_legacy_prop ufbxi_legacy_bone_props[] = {
  12929. { ufbxi_Size, UFBX_PROP_NUMBER, ufbxi_Size, "R" },
  12930. };
  12931. // Must be alphabetically sorted!
  12932. static const ufbxi_legacy_prop ufbxi_legacy_material_props[] = {
  12933. { ufbxi_AmbientColor, UFBX_PROP_COLOR, "Ambient", "RRR" },
  12934. { ufbxi_DiffuseColor, UFBX_PROP_COLOR, "Diffuse", "RRR" },
  12935. { ufbxi_EmissiveColor, UFBX_PROP_COLOR, "Emissive", "RRR" },
  12936. { ufbxi_ShadingModel, UFBX_PROP_COLOR, ufbxi_ShadingModel, "S" },
  12937. { ufbxi_Shininess, UFBX_PROP_NUMBER, "Shininess", "R" },
  12938. { ufbxi_SpecularColor, UFBX_PROP_COLOR, "Specular", "RRR" },
  12939. };
  12940. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_prop(ufbxi_node *node, ufbx_prop *prop, const ufbxi_legacy_prop *legacy_prop)
  12941. {
  12942. size_t value_ix = 0;
  12943. uint32_t flags = 0;
  12944. const char *fmt = legacy_prop->node_fmt;
  12945. for (size_t fmt_ix = 0; fmt[fmt_ix]; fmt_ix++) {
  12946. char c = fmt[fmt_ix];
  12947. switch (c) {
  12948. case 'L':
  12949. ufbx_assert(value_ix == 0);
  12950. if (!ufbxi_get_val_at(node, fmt_ix, 'L', &prop->value_int)) return 0;
  12951. prop->value_real = (ufbx_real)prop->value_int;
  12952. prop->value_real_arr[1] = 0.0f;
  12953. prop->value_real_arr[2] = 0.0f;
  12954. prop->value_real_arr[3] = 0.0f;
  12955. prop->value_str = ufbx_empty_string;
  12956. prop->value_blob = ufbx_empty_blob;
  12957. flags |= (uint32_t)UFBX_PROP_FLAG_VALUE_INT;
  12958. value_ix++;
  12959. break;
  12960. case 'R':
  12961. ufbx_assert(value_ix < 4);
  12962. if (!ufbxi_get_val_at(node, fmt_ix, 'R', &prop->value_real_arr[value_ix])) return 0;
  12963. if (value_ix == 0) {
  12964. prop->value_int = ufbxi_f64_to_i64(prop->value_real);
  12965. prop->value_real_arr[1] = 0.0f;
  12966. prop->value_real_arr[2] = 0.0f;
  12967. prop->value_real_arr[3] = 0.0f;
  12968. prop->value_str = ufbx_empty_string;
  12969. prop->value_blob = ufbx_empty_blob;
  12970. }
  12971. flags &= ~(uint32_t)(UFBX_PROP_FLAG_VALUE_REAL|UFBX_PROP_FLAG_VALUE_VEC2|UFBX_PROP_FLAG_VALUE_VEC3|UFBX_PROP_FLAG_VALUE_VEC4);
  12972. flags |= (uint32_t)UFBX_PROP_FLAG_VALUE_REAL << value_ix;
  12973. value_ix++;
  12974. break;
  12975. case 'S':
  12976. ufbx_assert(value_ix == 0);
  12977. if (!ufbxi_get_val_at(node, fmt_ix, 'S', &prop->value_str)) return 0;
  12978. if (prop->value_str.length > 0) {
  12979. int found = ufbxi_get_val_at(node, fmt_ix, 'b', &prop->value_blob);
  12980. ufbxi_ignore(found);
  12981. ufbx_assert(found);
  12982. } else {
  12983. prop->value_blob = ufbx_empty_blob;
  12984. }
  12985. prop->value_real = 0.0f;
  12986. prop->value_real_arr[1] = 0.0f;
  12987. prop->value_real_arr[2] = 0.0f;
  12988. prop->value_real_arr[3] = 0.0f;
  12989. prop->value_int = 0;
  12990. flags |= (uint32_t)UFBX_PROP_FLAG_VALUE_STR;
  12991. value_ix++;
  12992. break;
  12993. case '_':
  12994. break;
  12995. default:
  12996. ufbxi_unreachable("Unhandled legacy fmt");
  12997. }
  12998. }
  12999. prop->flags = (ufbx_prop_flags)flags;
  13000. return 1;
  13001. }
  13002. ufbxi_nodiscard ufbxi_noinline static size_t ufbxi_read_legacy_props(ufbxi_node *node, ufbx_prop *props, const ufbxi_legacy_prop *legacy_props, size_t num_legacy)
  13003. {
  13004. size_t num_props = 0;
  13005. for (size_t legacy_ix = 0; legacy_ix < num_legacy; legacy_ix++) {
  13006. const ufbxi_legacy_prop *legacy_prop = &legacy_props[legacy_ix];
  13007. ufbx_prop *prop = &props[num_props];
  13008. ufbxi_node *n = ufbxi_find_child_strcmp(node, legacy_prop->node_name);
  13009. if (!n) continue;
  13010. if (!ufbxi_read_legacy_prop(n, prop, legacy_prop)) continue;
  13011. prop->name.data = legacy_prop->prop_name;
  13012. prop->name.length = strlen(legacy_prop->prop_name);
  13013. prop->_internal_key = ufbxi_get_name_key(prop->name.data, prop->name.length);
  13014. prop->flags = (ufbx_prop_flags)0;
  13015. prop->type = legacy_prop->prop_type;
  13016. num_props++;
  13017. }
  13018. return num_props;
  13019. }
  13020. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_material(ufbxi_context *uc, ufbxi_node *node, uint64_t *p_fbx_id, const char *name)
  13021. {
  13022. ufbx_material *ufbxi_restrict material = ufbxi_push_synthetic_element(uc, p_fbx_id, node, name, ufbx_material, UFBX_ELEMENT_MATERIAL);
  13023. ufbxi_check(material);
  13024. ufbx_prop tmp_props[ufbxi_arraycount(ufbxi_legacy_material_props)];
  13025. size_t num_props = ufbxi_read_legacy_props(node, tmp_props, ufbxi_legacy_material_props, ufbxi_arraycount(ufbxi_legacy_material_props));
  13026. material->shading_model_name = ufbx_empty_string;
  13027. material->props.props.count = num_props;
  13028. material->props.props.data = ufbxi_push_copy(&uc->result, ufbx_prop, num_props, tmp_props);
  13029. ufbxi_check(material->props.props.data);
  13030. material->shader_prop_prefix = ufbx_empty_string;
  13031. return 1;
  13032. }
  13033. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_link(ufbxi_context *uc, ufbxi_node *node, uint64_t *p_fbx_id, const char *name)
  13034. {
  13035. ufbx_skin_cluster *ufbxi_restrict cluster = ufbxi_push_synthetic_element(uc, p_fbx_id, node, name, ufbx_skin_cluster, UFBX_ELEMENT_SKIN_CLUSTER);
  13036. ufbxi_check(cluster);
  13037. // TODO: Merge with ufbxi_read_skin_cluster(), at least partially?
  13038. ufbxi_value_array *indices = ufbxi_find_array(node, ufbxi_Indexes, 'i');
  13039. ufbxi_value_array *weights = ufbxi_find_array(node, ufbxi_Weights, 'r');
  13040. if (indices && weights) {
  13041. ufbxi_check(indices->size == weights->size);
  13042. cluster->num_weights = indices->size;
  13043. cluster->vertices.data = (uint32_t*)indices->data;
  13044. cluster->weights.data = (ufbx_real*)weights->data;
  13045. cluster->vertices.count = cluster->num_weights;
  13046. cluster->weights.count = cluster->num_weights;
  13047. }
  13048. ufbxi_value_array *transform = ufbxi_find_array(node, ufbxi_Transform, 'r');
  13049. ufbxi_value_array *transform_link = ufbxi_find_array(node, ufbxi_TransformLink, 'r');
  13050. if (transform && transform_link) {
  13051. ufbxi_check(transform->size >= 16);
  13052. ufbxi_check(transform_link->size >= 16);
  13053. ufbxi_read_transform_matrix(&cluster->mesh_node_to_bone, (ufbx_real*)transform->data);
  13054. ufbxi_read_transform_matrix(&cluster->bind_to_world, (ufbx_real*)transform_link->data);
  13055. }
  13056. return 1;
  13057. }
  13058. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_light(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  13059. {
  13060. ufbx_light *ufbxi_restrict light = ufbxi_push_element(uc, info, ufbx_light, UFBX_ELEMENT_LIGHT);
  13061. ufbxi_check(light);
  13062. ufbx_prop tmp_props[ufbxi_arraycount(ufbxi_legacy_light_props)];
  13063. size_t num_props = ufbxi_read_legacy_props(node, tmp_props, ufbxi_legacy_light_props, ufbxi_arraycount(ufbxi_legacy_light_props));
  13064. light->props.props.count = num_props;
  13065. light->props.props.data = ufbxi_push_copy(&uc->result, ufbx_prop, num_props, tmp_props);
  13066. ufbxi_check(light->props.props.data);
  13067. return 1;
  13068. }
  13069. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_camera(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  13070. {
  13071. ufbx_camera *ufbxi_restrict camera = ufbxi_push_element(uc, info, ufbx_camera, UFBX_ELEMENT_CAMERA);
  13072. ufbxi_check(camera);
  13073. ufbx_prop tmp_props[ufbxi_arraycount(ufbxi_legacy_camera_props)];
  13074. size_t num_props = ufbxi_read_legacy_props(node, tmp_props, ufbxi_legacy_camera_props, ufbxi_arraycount(ufbxi_legacy_camera_props));
  13075. camera->props.props.count = num_props;
  13076. camera->props.props.data = ufbxi_push_copy(&uc->result, ufbx_prop, num_props, tmp_props);
  13077. ufbxi_check(camera->props.props.data);
  13078. return 1;
  13079. }
  13080. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_limb_node(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  13081. {
  13082. ufbx_bone *ufbxi_restrict bone = ufbxi_push_element(uc, info, ufbx_bone, UFBX_ELEMENT_BONE);
  13083. ufbxi_check(bone);
  13084. ufbx_prop tmp_props[ufbxi_arraycount(ufbxi_legacy_bone_props)];
  13085. size_t num_props = 0;
  13086. ufbxi_node *prop_node = ufbxi_find_child_strcmp(node, "Properties");
  13087. if (prop_node) {
  13088. num_props = ufbxi_read_legacy_props(prop_node, tmp_props, ufbxi_legacy_bone_props, ufbxi_arraycount(ufbxi_legacy_bone_props));
  13089. }
  13090. bone->props.props.count = num_props;
  13091. bone->props.props.data = ufbxi_push_copy(&uc->result, ufbx_prop, num_props, tmp_props);
  13092. ufbxi_check(bone->props.props.data);
  13093. return 1;
  13094. }
  13095. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_mesh(ufbxi_context *uc, ufbxi_node *node, ufbxi_element_info *info)
  13096. {
  13097. // Only read polygon meshes, ignore eg. NURBS without error
  13098. ufbxi_node *node_vertices = ufbxi_find_child(node, ufbxi_Vertices);
  13099. ufbxi_node *node_indices = ufbxi_find_child(node, ufbxi_PolygonVertexIndex);
  13100. if (!node_vertices || !node_indices) return 1;
  13101. ufbx_mesh *ufbxi_restrict mesh = ufbxi_push_element(uc, info, ufbx_mesh, UFBX_ELEMENT_MESH);
  13102. ufbxi_check(mesh);
  13103. ufbxi_check(ufbxi_read_synthetic_blend_shapes(uc, node, info));
  13104. ufbxi_patch_mesh_reals(mesh);
  13105. if (uc->opts.ignore_geometry) return 1;
  13106. ufbxi_value_array *vertices = ufbxi_get_array(node_vertices, 'r');
  13107. ufbxi_value_array *indices = ufbxi_get_array(node_indices, 'i');
  13108. ufbxi_check(vertices && indices);
  13109. ufbxi_check(vertices->size % 3 == 0);
  13110. mesh->num_vertices = vertices->size / 3;
  13111. mesh->num_indices = indices->size;
  13112. uint32_t *index_data = (uint32_t*)indices->data;
  13113. // Duplicate `index_data` for modification if we retain DOM
  13114. if (uc->opts.retain_dom) {
  13115. index_data = ufbxi_push_copy(&uc->result, uint32_t, indices->size, index_data);
  13116. ufbxi_check(index_data);
  13117. }
  13118. mesh->vertices.data = (ufbx_vec3*)vertices->data;
  13119. mesh->vertex_indices.data = index_data;
  13120. mesh->vertices.count = mesh->num_vertices;
  13121. mesh->vertex_indices.count = mesh->num_indices;
  13122. mesh->vertex_position.exists = true;
  13123. mesh->vertex_position.values.data = (ufbx_vec3*)vertices->data;
  13124. mesh->vertex_position.values.count = mesh->num_vertices;
  13125. mesh->vertex_position.indices.data = index_data;
  13126. mesh->vertex_position.indices.count = mesh->num_indices;
  13127. mesh->vertex_position.unique_per_vertex = true;
  13128. // Check/make sure that the last index is negated (last of polygon)
  13129. if (mesh->num_indices > 0) {
  13130. if ((int32_t)index_data[mesh->num_indices - 1] >= 0) {
  13131. if (uc->opts.strict) ufbxi_fail("Non-negated last index");
  13132. index_data[mesh->num_indices - 1] = ~index_data[mesh->num_indices - 1];
  13133. }
  13134. }
  13135. ufbxi_check(ufbxi_process_indices(uc, mesh, index_data));
  13136. // Normals are either per-vertex or per-index in legacy FBX files?
  13137. // If the version is 5000 prefer per-vertex, otherwise per-index...
  13138. ufbxi_value_array *normals = ufbxi_find_array(node, ufbxi_Normals, 'r');
  13139. if (normals) {
  13140. size_t num_normals = normals->size / 3;
  13141. bool per_vertex = num_normals == mesh->num_vertices;
  13142. bool per_index = num_normals == mesh->num_indices;
  13143. if (per_vertex && (!per_index || uc->version == 5000)) {
  13144. mesh->vertex_normal.exists = true;
  13145. mesh->vertex_normal.values.count = num_normals;
  13146. mesh->vertex_normal.indices.count = mesh->num_indices;
  13147. mesh->vertex_normal.unique_per_vertex = true;
  13148. mesh->vertex_normal.values.data = (ufbx_vec3*)normals->data;
  13149. mesh->vertex_normal.indices.data = mesh->vertex_indices.data;
  13150. } else if (per_index) {
  13151. uc->max_consecutive_indices = ufbxi_max_sz(uc->max_consecutive_indices, mesh->num_indices);
  13152. mesh->vertex_normal.exists = true;
  13153. mesh->vertex_normal.values.count = num_normals;
  13154. mesh->vertex_normal.indices.count = mesh->num_indices;
  13155. mesh->vertex_normal.unique_per_vertex = false;
  13156. mesh->vertex_normal.values.data = (ufbx_vec3*)normals->data;
  13157. mesh->vertex_normal.indices.data = (uint32_t*)ufbxi_sentinel_index_consecutive;
  13158. }
  13159. }
  13160. // Optional UV values are stored pretty much like a modern vertex element
  13161. ufbxi_node *uv_info = ufbxi_find_child(node, ufbxi_GeometryUVInfo);
  13162. if (uv_info) {
  13163. ufbx_uv_set *set = ufbxi_push_zero(&uc->result, ufbx_uv_set, 1);
  13164. ufbxi_check(set);
  13165. set->index = 0;
  13166. set->name.data = ufbxi_empty_char;
  13167. ufbxi_check(ufbxi_read_vertex_element(uc, mesh, uv_info, (ufbx_vertex_attrib*)&set->vertex_uv,
  13168. ufbxi_TextureUV, ufbxi_TextureUVVerticeIndex, NULL, 'r', 2));
  13169. mesh->uv_sets.data = set;
  13170. mesh->uv_sets.count = 1;
  13171. mesh->vertex_uv = set->vertex_uv;
  13172. }
  13173. // Material indices
  13174. {
  13175. const char *mapping = NULL;
  13176. ufbxi_check(ufbxi_find_val1(node, ufbxi_MaterialAssignation, "C", (char**)&mapping));
  13177. if (mapping == ufbxi_ByPolygon) {
  13178. ufbxi_check(ufbxi_read_truncated_array(uc, &mesh->face_material.data, &mesh->face_material.count, node, ufbxi_Materials, 'i', mesh->num_faces));
  13179. } else if (mapping == ufbxi_AllSame) {
  13180. ufbxi_value_array *arr = ufbxi_find_array(node, ufbxi_Materials, 'i');
  13181. uint32_t material = 0;
  13182. if (arr && arr->size >= 1) {
  13183. material = ((uint32_t*)arr->data)[0];
  13184. }
  13185. mesh->face_material.count = mesh->num_faces;
  13186. if (material == 0) {
  13187. mesh->face_material.data = (uint32_t*)ufbxi_sentinel_index_zero;
  13188. } else {
  13189. mesh->face_material.data = ufbxi_push(&uc->result, uint32_t, mesh->num_faces);
  13190. ufbxi_check(mesh->face_material.data);
  13191. ufbxi_for_list(uint32_t, p_mat, mesh->face_material) {
  13192. *p_mat = material;
  13193. }
  13194. }
  13195. }
  13196. }
  13197. uint64_t skin_fbx_id = 0;
  13198. ufbx_skin_deformer *skin = NULL;
  13199. // Materials, Skin Clusters
  13200. ufbxi_for(ufbxi_node, child, node->children, node->num_children) {
  13201. if (child->name == ufbxi_Material) {
  13202. uint64_t fbx_id = 0;
  13203. ufbx_string type_and_name, type, name;
  13204. ufbxi_check(ufbxi_get_val1(child, "s", &type_and_name));
  13205. ufbxi_check(ufbxi_split_type_and_name(uc, type_and_name, &type, &name));
  13206. ufbxi_check(ufbxi_read_legacy_material(uc, child, &fbx_id, name.data));
  13207. ufbxi_check(ufbxi_connect_oo(uc, fbx_id, info->fbx_id));
  13208. } else if (child->name == ufbxi_Link) {
  13209. uint64_t fbx_id = 0;
  13210. ufbx_string type_and_name, type, name;
  13211. ufbxi_check(ufbxi_get_val1(child, "s", &type_and_name));
  13212. ufbxi_check(ufbxi_split_type_and_name(uc, type_and_name, &type, &name));
  13213. ufbxi_check(ufbxi_read_legacy_link(uc, child, &fbx_id, name.data));
  13214. uint64_t node_fbx_id = ufbxi_synthetic_id_from_string(type_and_name.data);
  13215. ufbxi_check(ufbxi_connect_oo(uc, node_fbx_id, fbx_id));
  13216. if (!skin) {
  13217. skin = ufbxi_push_synthetic_element(uc, &skin_fbx_id, NULL, info->name.data, ufbx_skin_deformer, UFBX_ELEMENT_SKIN_DEFORMER);
  13218. ufbxi_check(skin);
  13219. ufbxi_check(ufbxi_connect_oo(uc, skin_fbx_id, info->fbx_id));
  13220. }
  13221. ufbxi_check(ufbxi_connect_oo(uc, fbx_id, skin_fbx_id));
  13222. }
  13223. }
  13224. mesh->skinned_is_local = true;
  13225. mesh->skinned_position = mesh->vertex_position;
  13226. mesh->skinned_normal = mesh->vertex_normal;
  13227. ufbxi_patch_mesh_reals(mesh);
  13228. return 1;
  13229. }
  13230. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_media(ufbxi_context *uc, ufbxi_node *node)
  13231. {
  13232. ufbxi_node *videos = ufbxi_find_child(node, ufbxi_Video);
  13233. if (videos) {
  13234. ufbxi_for(ufbxi_node, child, videos->children, videos->num_children) {
  13235. ufbxi_element_info video_info = { 0 };
  13236. ufbxi_check(ufbxi_get_val1(child, "S", &video_info.name));
  13237. ufbxi_check(ufbxi_push_synthetic_id(uc, &video_info.fbx_id));
  13238. video_info.dom_node = ufbxi_get_dom_node(uc, node);
  13239. ufbxi_check(ufbxi_read_video(uc, child, &video_info));
  13240. }
  13241. }
  13242. return 1;
  13243. }
  13244. ufbxi_nodiscard ufbxi_noinline static int ufbxi_read_legacy_model(ufbxi_context *uc, ufbxi_node *node)
  13245. {
  13246. ufbx_string type_and_name, type, name;
  13247. ufbxi_check(ufbxi_get_val1(node, "s", &type_and_name));
  13248. ufbxi_check(ufbxi_split_type_and_name(uc, type_and_name, &type, &name));
  13249. ufbxi_element_info info = { 0 };
  13250. info.fbx_id = ufbxi_synthetic_id_from_string(type_and_name.data);
  13251. info.name = name;
  13252. info.dom_node = ufbxi_get_dom_node(uc, node);
  13253. ufbx_node *elem_node = ufbxi_push_element(uc, &info, ufbx_node, UFBX_ELEMENT_NODE);
  13254. ufbxi_check(elem_node);
  13255. ufbxi_check(ufbxi_push_copy(&uc->tmp_node_ids, uint32_t, 1, &elem_node->element.element_id));
  13256. ufbxi_element_info attrib_info = { 0 };
  13257. ufbxi_check(ufbxi_push_synthetic_id(uc, &attrib_info.fbx_id));
  13258. attrib_info.name = name;
  13259. attrib_info.dom_node = info.dom_node;
  13260. // If we make unused connections it doesn't matter..
  13261. ufbxi_check(ufbxi_connect_oo(uc, attrib_info.fbx_id, info.fbx_id));
  13262. const char *attrib_type = ufbxi_empty_char;
  13263. ufbxi_ignore(ufbxi_find_val1(node, ufbxi_Type, "C", (char**)&attrib_type));
  13264. bool has_attrib = true;
  13265. if (attrib_type == ufbxi_Light) {
  13266. ufbxi_check(ufbxi_read_legacy_light(uc, node, &attrib_info));
  13267. } else if (attrib_type == ufbxi_Camera) {
  13268. ufbxi_check(ufbxi_read_legacy_camera(uc, node, &attrib_info));
  13269. } else if (attrib_type == ufbxi_LimbNode) {
  13270. ufbxi_check(ufbxi_read_legacy_limb_node(uc, node, &attrib_info));
  13271. } else if (ufbxi_find_child(node, ufbxi_Vertices)) {
  13272. ufbxi_check(ufbxi_read_legacy_mesh(uc, node, &attrib_info));
  13273. } else {
  13274. has_attrib = false;
  13275. }
  13276. // Mark the node as having an attribute so property connections can be forwarded
  13277. if (has_attrib) {
  13278. ufbxi_check(ufbxi_insert_fbx_attr(uc, info.fbx_id, attrib_info.fbx_id));
  13279. }
  13280. // Children are represented as an array of strings
  13281. ufbxi_value_array *children = ufbxi_find_array(node, ufbxi_Children, 's');
  13282. if (children) {
  13283. ufbx_string *names = (ufbx_string*)children->data;
  13284. for (size_t i = 0; i < children->size; i++) {
  13285. uint64_t child_fbx_id = ufbxi_synthetic_id_from_string(names[i].data);
  13286. ufbxi_check(ufbxi_connect_oo(uc, child_fbx_id, info.fbx_id));
  13287. }
  13288. }
  13289. // Non-take animation channels
  13290. ufbxi_for(ufbxi_node, child, node->children, node->num_children) {
  13291. if (child->name == ufbxi_Channel) {
  13292. ufbx_string channel_name;
  13293. if (ufbxi_get_val1(child, "S", &channel_name)) {
  13294. if (uc->legacy_implicit_anim_layer_id == 0) {
  13295. // Defer creation so we won't be the first animation stack..
  13296. ufbxi_check(ufbxi_push_synthetic_id(uc, &uc->legacy_implicit_anim_layer_id));
  13297. }
  13298. ufbxi_check(ufbxi_read_take_prop_channel(uc, child, info.fbx_id, uc->legacy_implicit_anim_layer_id, channel_name));
  13299. }
  13300. }
  13301. }
  13302. return 1;
  13303. }
  13304. // Read a pre-6000 FBX file where everything is stored at the root level
  13305. ufbxi_nodiscard static ufbxi_noinline int ufbxi_read_legacy_root(ufbxi_context *uc)
  13306. {
  13307. ufbxi_check(ufbxi_init_node_prop_names(uc));
  13308. // Some legacy FBX files have an `Fbx_Root` node that could be used as the
  13309. // root node. However no other formats have root node with transforms so it
  13310. // might be better to leave it as-is and create an empty one.
  13311. {
  13312. ufbx_node *root = ufbxi_push_synthetic_element(uc, &uc->root_id, NULL, ufbxi_empty_char, ufbx_node, UFBX_ELEMENT_NODE);
  13313. ufbxi_check(root);
  13314. ufbxi_setup_root_node(uc, root);
  13315. ufbxi_check(ufbxi_push_copy(&uc->tmp_node_ids, uint32_t, 1, &root->element.element_id));
  13316. }
  13317. // NOTE: `ufbxi_read_header_extension()` is optional so use default KTime definition
  13318. uc->ktime_sec = 46186158000;
  13319. uc->ktime_sec_double = (double)uc->ktime_sec;
  13320. for (;;) {
  13321. ufbxi_check(ufbxi_parse_legacy_toplevel(uc));
  13322. if (!uc->top_node) break;
  13323. ufbxi_node *node = uc->top_node;
  13324. if (node->name == ufbxi_FBXHeaderExtension) {
  13325. ufbxi_check(ufbxi_read_header_extension(uc));
  13326. } else if (node->name == ufbxi_Media) {
  13327. ufbxi_check(ufbxi_read_legacy_media(uc, node));
  13328. } else if (node->name == ufbxi_Takes) {
  13329. ufbxi_check(ufbxi_read_takes(uc));
  13330. } else if (node->name == ufbxi_Model) {
  13331. ufbxi_check(ufbxi_read_legacy_model(uc, node));
  13332. } else if (!strcmp(node->name, "Settings")) {
  13333. ufbxi_check(ufbxi_read_legacy_settings(uc, node));
  13334. }
  13335. }
  13336. if (uc->opts.retain_dom) {
  13337. ufbxi_check(ufbxi_retain_toplevel(uc, NULL));
  13338. }
  13339. // Create the implicit animation stack if necessary
  13340. if (uc->legacy_implicit_anim_layer_id) {
  13341. ufbxi_element_info layer_info = { 0 };
  13342. layer_info.fbx_id = uc->legacy_implicit_anim_layer_id;
  13343. layer_info.name.data = "(internal)";
  13344. layer_info.name.length = strlen(layer_info.name.data);
  13345. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &layer_info.name, true));
  13346. ufbx_anim_layer *layer = ufbxi_push_element(uc, &layer_info, ufbx_anim_layer, UFBX_ELEMENT_ANIM_LAYER);
  13347. ufbxi_check(layer);
  13348. ufbxi_element_info stack_info = layer_info;
  13349. ufbxi_check(ufbxi_push_synthetic_id(uc, &stack_info.fbx_id));
  13350. ufbx_anim_stack *stack = ufbxi_push_element(uc, &stack_info, ufbx_anim_stack, UFBX_ELEMENT_ANIM_STACK);
  13351. ufbxi_check(stack);
  13352. ufbxi_check(ufbxi_connect_oo(uc, layer_info.fbx_id, stack_info.fbx_id));
  13353. }
  13354. return 1;
  13355. }
  13356. // Filename manipulation
  13357. ufbxi_nodiscard ufbxi_noinline static size_t ufbxi_trim_delimiters(ufbxi_context *uc, const char *data, size_t length)
  13358. {
  13359. for (; length > 0; length--) {
  13360. char c = data[length - 1];
  13361. bool is_separator = c == '/' || c == uc->opts.path_separator;
  13362. if (is_separator) {
  13363. length--;
  13364. break;
  13365. }
  13366. }
  13367. return length;
  13368. }
  13369. ufbxi_nodiscard ufbxi_noinline static int ufbxi_init_file_paths(ufbxi_context *uc)
  13370. {
  13371. if (uc->opts.filename.length > 0) {
  13372. uc->scene.metadata.filename = uc->opts.filename;
  13373. } else if (uc->opts.raw_filename.size > 0) {
  13374. uc->scene.metadata.filename.data = (const char*)uc->opts.raw_filename.data;
  13375. uc->scene.metadata.filename.length = uc->opts.raw_filename.size;
  13376. }
  13377. if (uc->opts.raw_filename.size > 0) {
  13378. uc->scene.metadata.raw_filename = uc->opts.raw_filename;
  13379. } else if (uc->opts.filename.length > 0) {
  13380. uc->scene.metadata.raw_filename.data = uc->opts.filename.data;
  13381. uc->scene.metadata.raw_filename.size = uc->opts.filename.length;
  13382. }
  13383. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &uc->scene.metadata.filename, false));
  13384. ufbxi_check(ufbxi_push_string_place_blob(&uc->string_pool, &uc->scene.metadata.raw_filename, true));
  13385. uc->scene.metadata.relative_root.data = uc->scene.metadata.filename.data;
  13386. uc->scene.metadata.relative_root.length = ufbxi_trim_delimiters(uc, uc->scene.metadata.filename.data, uc->scene.metadata.filename.length);
  13387. uc->scene.metadata.raw_relative_root.data = uc->scene.metadata.raw_filename.data;
  13388. uc->scene.metadata.raw_relative_root.size = ufbxi_trim_delimiters(uc, (const char*)uc->scene.metadata.raw_filename.data, uc->scene.metadata.raw_filename.size);
  13389. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &uc->scene.metadata.relative_root, false));
  13390. ufbxi_check(ufbxi_push_string_place_blob(&uc->string_pool, &uc->scene.metadata.raw_relative_root, true));
  13391. return 1;
  13392. }
  13393. typedef union {
  13394. ufbx_string str;
  13395. ufbx_blob blob;
  13396. } ufbxi_strblob;
  13397. static ufbxi_noinline void ufbxi_strblob_set(ufbxi_strblob *dst, const char *data, size_t length, bool raw)
  13398. {
  13399. if (raw) {
  13400. dst->blob.data = data;
  13401. dst->blob.size = length;
  13402. } else {
  13403. dst->str.data = length == 0 ? ufbxi_empty_char : data;
  13404. dst->str.length = length;
  13405. }
  13406. }
  13407. static ufbxi_forceinline const char *ufbxi_strblob_data(const ufbxi_strblob *strblob, bool raw)
  13408. {
  13409. return raw ? (const char*)strblob->blob.data : strblob->str.data;
  13410. }
  13411. static ufbxi_forceinline size_t ufbxi_strblob_length(const ufbxi_strblob *strblob, bool raw)
  13412. {
  13413. return raw ? strblob->blob.size : strblob->str.length;
  13414. }
  13415. ufbxi_nodiscard ufbxi_noinline static bool ufbxi_is_absolute_path(const char *path, size_t length)
  13416. {
  13417. if (length > 0 && (path[0] == '/' || path[0] == '\\')) {
  13418. return true;
  13419. } else if (length > 2 && path[1] == ':' && (path[2] == '\\' || path[2] == '/')) {
  13420. return true;
  13421. }
  13422. return false;
  13423. }
  13424. ufbxi_nodiscard ufbxi_noinline static int ufbxi_resolve_relative_filename(ufbxi_context *uc, ufbxi_strblob *p_dst, const ufbxi_strblob *p_src, bool raw)
  13425. {
  13426. const char *src = ufbxi_strblob_data(p_src, raw);
  13427. size_t src_length = ufbxi_strblob_length(p_src, raw);
  13428. // Skip leading directory separators and early return if the relative path is empty
  13429. while (src_length > 0 && (src[0] == '/' || src[0] == '\\')) {
  13430. src++;
  13431. src_length--;
  13432. }
  13433. if (src_length == 0) {
  13434. ufbxi_strblob_set(p_dst, NULL, 0, raw);
  13435. return 1;
  13436. }
  13437. const char *prefix_data;
  13438. size_t prefix_length;
  13439. if (raw) {
  13440. prefix_data = (const char*)uc->scene.metadata.raw_relative_root.data;
  13441. prefix_length = uc->scene.metadata.raw_relative_root.size;
  13442. } else {
  13443. prefix_data = (const char*)uc->scene.metadata.relative_root.data;
  13444. prefix_length = uc->scene.metadata.relative_root.length;
  13445. }
  13446. // Retain absolute paths
  13447. if (ufbxi_is_absolute_path(src, src_length)) {
  13448. prefix_length = 0;
  13449. }
  13450. // Undo directories from `prefix` for every `..`
  13451. while (prefix_length > 0 && src_length >= 3 && src[0] == '.' && src[1] == '.' && (src[2] == '/' || src[2] == '\\')) {
  13452. size_t part_start = prefix_length;
  13453. while (part_start > 0 && !(prefix_data[part_start - 1] == '/' || prefix_data[part_start - 1] == '\\')) {
  13454. part_start--;
  13455. }
  13456. size_t part_len = prefix_length - part_start;
  13457. if (part_len == 2 && prefix_data[part_start] == '.' && prefix_data[part_start + 1] == '.') {
  13458. // Prefix itself ends in `..`, cannot cancel out a leading `../`
  13459. break;
  13460. }
  13461. // Eat the leading '/' before the part segment
  13462. prefix_length = part_start > 0 ? part_start - 1 : 0;
  13463. if (part_len == 1 && prefix_data[part_start] == '.') {
  13464. // Single '.' -> remove and continue without cancelling out a leading `../`
  13465. continue;
  13466. }
  13467. src += 3;
  13468. src_length -= 3;
  13469. }
  13470. size_t result_cap = prefix_length + src_length + 1;
  13471. char *result = ufbxi_push(&uc->tmp_stack, char, result_cap);
  13472. ufbxi_check(result);
  13473. char *ptr = result;
  13474. // Copy prefix and suffix converting separators in the process
  13475. if (prefix_length > 0) {
  13476. memcpy(ptr, prefix_data, prefix_length);
  13477. ptr[prefix_length] = uc->opts.path_separator;
  13478. ptr += prefix_length + 1;
  13479. }
  13480. for (size_t i = 0; i < src_length; i++) {
  13481. char c = src[i];
  13482. if (c == '/' || c == '\\') {
  13483. c = uc->opts.path_separator;
  13484. }
  13485. *ptr++ = c;
  13486. }
  13487. // Intern the string and pop the temporary buffer
  13488. ufbx_string dst = { result, ufbxi_to_size(ptr - result) };
  13489. ufbx_assert(dst.length <= result_cap);
  13490. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &dst, raw));
  13491. ufbxi_pop(&uc->tmp_stack, char, result_cap, NULL);
  13492. ufbxi_strblob_set(p_dst, dst.data, dst.length, raw);
  13493. return 1;
  13494. }
  13495. // Open file utility
  13496. static void *ufbxi_ator_alloc(void *user, size_t size)
  13497. {
  13498. ufbxi_allocator *ator = (ufbxi_allocator*)user;
  13499. return ufbxi_alloc(ator, char, size);
  13500. }
  13501. static void *ufbxi_ator_realloc(void *user, void *old_ptr, size_t old_size, size_t new_size)
  13502. {
  13503. ufbxi_allocator *ator = (ufbxi_allocator*)user;
  13504. return ufbxi_realloc(ator, char, old_ptr, old_size, new_size);
  13505. }
  13506. static void ufbxi_ator_free(void *user, void *ptr, size_t size)
  13507. {
  13508. ufbxi_allocator *ator = (ufbxi_allocator*)user;
  13509. ufbxi_free(ator, char, ptr, size);
  13510. }
  13511. static ufbxi_noinline void ufbxi_setup_ator_allocator(ufbx_allocator *allocator, ufbxi_allocator *ator)
  13512. {
  13513. allocator->alloc_fn = &ufbxi_ator_alloc;
  13514. allocator->realloc_fn = &ufbxi_ator_realloc;
  13515. allocator->free_fn = &ufbxi_ator_free;
  13516. allocator->free_allocator_fn = NULL;
  13517. allocator->user = ator;
  13518. }
  13519. static ufbxi_noinline bool ufbxi_open_file(const ufbx_open_file_cb *cb, ufbx_stream *stream, const char *path, size_t path_len, const ufbx_blob *original_filename, ufbxi_allocator *ator, ufbx_open_file_type type)
  13520. {
  13521. if (!cb || !cb->fn) return false;
  13522. ufbx_open_file_info info; // ufbxi_uninit
  13523. if (ator) {
  13524. ufbxi_setup_ator_allocator(&info.temp_allocator, ator);
  13525. } else {
  13526. memset(&info.temp_allocator, 0, sizeof(info.temp_allocator));
  13527. }
  13528. if (original_filename) {
  13529. info.original_filename = *original_filename;
  13530. } else {
  13531. info.original_filename.data = path;
  13532. info.original_filename.size = path_len;
  13533. }
  13534. info.type = type;
  13535. return cb->fn(cb->user, stream, path, path_len, &info);
  13536. }
  13537. #define ufbxi_patch_zero(dst, src) do { \
  13538. ufbx_assert((dst) == 0 || (dst) == (src)); \
  13539. (dst) = (src); \
  13540. } while (0)
  13541. static void ufbxi_update_vertex_first_index(ufbx_mesh *mesh)
  13542. {
  13543. ufbxi_for_list(uint32_t, p_vx_ix, mesh->vertex_first_index) {
  13544. *p_vx_ix = UFBX_NO_INDEX;
  13545. }
  13546. uint32_t num_vertices = (uint32_t)mesh->num_vertices;
  13547. for (size_t ix = 0; ix < mesh->num_indices; ix++) {
  13548. uint32_t vx = mesh->vertex_indices.data[ix];
  13549. if (vx < num_vertices && mesh->vertex_first_index.data[vx] == UFBX_NO_INDEX) {
  13550. mesh->vertex_first_index.data[vx] = (uint32_t)ix;
  13551. }
  13552. }
  13553. }
  13554. ufbxi_nodiscard static ufbxi_noinline int ufbxi_finalize_mesh(ufbxi_buf *buf, ufbx_error *error, ufbx_mesh *mesh)
  13555. {
  13556. if (mesh->vertices.count == 0) {
  13557. mesh->vertices = mesh->vertex_position.values;
  13558. }
  13559. if (mesh->vertex_indices.count == 0) {
  13560. mesh->vertex_indices = mesh->vertex_position.indices;
  13561. }
  13562. ufbxi_patch_zero(mesh->num_vertices, mesh->vertices.count);
  13563. ufbxi_patch_zero(mesh->num_indices, mesh->vertex_indices.count);
  13564. ufbxi_patch_zero(mesh->num_faces, mesh->faces.count);
  13565. if (mesh->num_triangles == 0 || mesh->max_face_triangles == 0) {
  13566. size_t num_triangles = 0;
  13567. size_t max_face_triangles = 0;
  13568. size_t num_bad_faces[3] = { 0 };
  13569. ufbxi_nounroll ufbxi_for_list(ufbx_face, face, mesh->faces) {
  13570. if (face->num_indices >= 3) {
  13571. size_t tris = face->num_indices - 2;
  13572. num_triangles += tris;
  13573. max_face_triangles = ufbxi_max_sz(max_face_triangles, tris);
  13574. } else {
  13575. num_bad_faces[face->num_indices]++;
  13576. }
  13577. }
  13578. ufbxi_patch_zero(mesh->num_triangles, num_triangles);
  13579. ufbxi_patch_zero(mesh->max_face_triangles, max_face_triangles);
  13580. ufbxi_patch_zero(mesh->num_empty_faces, num_bad_faces[0]);
  13581. ufbxi_patch_zero(mesh->num_point_faces, num_bad_faces[1]);
  13582. ufbxi_patch_zero(mesh->num_line_faces, num_bad_faces[2]);
  13583. }
  13584. if (!mesh->skinned_position.exists) {
  13585. mesh->skinned_is_local = true;
  13586. mesh->skinned_position = mesh->vertex_position;
  13587. mesh->skinned_normal = mesh->vertex_normal;
  13588. }
  13589. if (mesh->vertex_first_index.count == 0) {
  13590. mesh->vertex_first_index.count = mesh->num_vertices;
  13591. mesh->vertex_first_index.data = ufbxi_push(buf, uint32_t, mesh->num_vertices);
  13592. ufbxi_check_err(error, mesh->vertex_first_index.data);
  13593. ufbxi_update_vertex_first_index(mesh);
  13594. }
  13595. if (mesh->uv_sets.count == 0 && mesh->vertex_uv.exists) {
  13596. ufbx_uv_set *uv_set = ufbxi_push_zero(buf, ufbx_uv_set, 1);
  13597. ufbxi_check_err(error, uv_set);
  13598. uv_set->name.data = ufbxi_empty_char;
  13599. uv_set->vertex_uv = mesh->vertex_uv;
  13600. uv_set->vertex_tangent = mesh->vertex_tangent;
  13601. uv_set->vertex_bitangent = mesh->vertex_bitangent;
  13602. mesh->uv_sets.data = uv_set;
  13603. mesh->uv_sets.count = 1;
  13604. }
  13605. if (mesh->color_sets.count == 0 && mesh->vertex_color.exists) {
  13606. ufbx_color_set *color_set = ufbxi_push_zero(buf, ufbx_color_set, 1);
  13607. ufbxi_check_err(error, color_set);
  13608. color_set->name.data = ufbxi_empty_char;
  13609. color_set->vertex_color = mesh->vertex_color;
  13610. mesh->color_sets.data = color_set;
  13611. mesh->color_sets.count = 1;
  13612. }
  13613. ufbxi_patch_mesh_reals(mesh);
  13614. return 1;
  13615. }
  13616. // -- .obj file
  13617. #if UFBXI_FEATURE_FORMAT_OBJ
  13618. static const uint8_t ufbxi_obj_attrib_stride[] = {
  13619. 3, 2, 3, 4,
  13620. };
  13621. ufbx_static_assert(obj_attrib_strides, ufbxi_arraycount(ufbxi_obj_attrib_stride) == UFBXI_OBJ_NUM_ATTRIBS_EXT);
  13622. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_pop_props(ufbxi_context *uc, ufbx_prop_list *dst, size_t count)
  13623. {
  13624. ufbx_prop_list props; // ufbxi_uninit
  13625. props.count = count;
  13626. props.data = ufbxi_push_pop(&uc->result, &uc->obj.tmp_props, ufbx_prop, count);
  13627. ufbxi_check(props.data);
  13628. ufbxi_for_list(ufbx_prop, prop, props) {
  13629. prop->_internal_key = ufbxi_get_name_key(prop->name.data, prop->name.length);
  13630. if (prop->value_str.length == 0) {
  13631. prop->value_str.data = ufbxi_empty_char;
  13632. }
  13633. if (!prop->value_int) {
  13634. prop->value_int = ufbxi_f64_to_i64(prop->value_real);
  13635. }
  13636. if (prop->value_blob.size == 0 && prop->value_str.length > 0) {
  13637. prop->value_blob.data = prop->value_str.data;
  13638. prop->value_blob.size = prop->value_str.length;
  13639. }
  13640. }
  13641. if (props.count > 1) {
  13642. ufbxi_check(ufbxi_sort_properties(uc, props.data, props.count));
  13643. ufbxi_deduplicate_properties(&props);
  13644. }
  13645. *dst = props;
  13646. return 1;
  13647. }
  13648. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_push_mesh(ufbxi_context *uc)
  13649. {
  13650. ufbxi_obj_mesh *mesh = ufbxi_push_zero(&uc->obj.tmp_meshes, ufbxi_obj_mesh, 1);
  13651. ufbxi_check(mesh);
  13652. uc->obj.mesh = mesh;
  13653. ufbxi_nounroll for (size_t i = 0; i < UFBXI_OBJ_NUM_ATTRIBS; i++) {
  13654. mesh->vertex_range[i].min_ix = UINT64_MAX;
  13655. }
  13656. const char *name = "";
  13657. if (uc->opts.obj_split_groups && uc->obj.group.length > 0) {
  13658. name = uc->obj.group.data;
  13659. } else if (!uc->opts.obj_merge_objects && uc->obj.object.length > 0) {
  13660. name = uc->obj.object.data;
  13661. } else if (!uc->opts.obj_merge_groups && uc->obj.group.length > 0) {
  13662. name = uc->obj.group.data;
  13663. }
  13664. mesh->fbx_node = ufbxi_push_synthetic_element(uc, &mesh->fbx_node_id, NULL, name, ufbx_node, UFBX_ELEMENT_NODE);
  13665. mesh->fbx_mesh = ufbxi_push_synthetic_element(uc, &mesh->fbx_mesh_id, NULL, name, ufbx_mesh, UFBX_ELEMENT_MESH);
  13666. ufbxi_check(mesh->fbx_node && mesh->fbx_mesh);
  13667. mesh->fbx_mesh->vertex_position.unique_per_vertex = true;
  13668. ufbxi_check(ufbxi_push_copy(&uc->tmp_node_ids, uint32_t, 1, &mesh->fbx_node->element_id));
  13669. uc->obj.face_material = UFBX_NO_INDEX;
  13670. uc->obj.face_group = 0;
  13671. uc->obj.face_group_dirty = true;
  13672. uc->obj.material_dirty = true;
  13673. ufbxi_check(ufbxi_connect_oo(uc, mesh->fbx_mesh_id, mesh->fbx_node_id));
  13674. ufbxi_check(ufbxi_connect_oo(uc, mesh->fbx_node_id, 0));
  13675. return 1;
  13676. }
  13677. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_flush_mesh(ufbxi_context *uc)
  13678. {
  13679. if (!uc->obj.mesh) return 1;
  13680. size_t num_props = uc->obj.tmp_props.num_items;
  13681. ufbxi_check(ufbxi_obj_pop_props(uc, &uc->obj.mesh->fbx_mesh->props.props, num_props));
  13682. size_t num_groups = uc->obj.tmp_face_group_infos.num_items;
  13683. ufbx_face_group *groups = ufbxi_push_pop(&uc->result, &uc->obj.tmp_face_group_infos, ufbx_face_group, num_groups);
  13684. ufbxi_check(groups);
  13685. uc->obj.mesh->fbx_mesh->face_groups.data = groups;
  13686. uc->obj.mesh->fbx_mesh->face_groups.count = num_groups;
  13687. return 1;
  13688. }
  13689. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_init(ufbxi_context *uc)
  13690. {
  13691. uc->from_ascii = true;
  13692. uc->obj.initialized = true;
  13693. ufbxi_nounroll for (size_t i = 0; i < UFBXI_OBJ_NUM_ATTRIBS_EXT; i++) {
  13694. uc->obj.tmp_vertices[i].ator = &uc->ator_tmp;
  13695. uc->obj.tmp_indices[i].ator = &uc->ator_tmp;
  13696. }
  13697. uc->obj.tmp_color_valid.ator = &uc->ator_tmp;
  13698. uc->obj.tmp_faces.ator = &uc->ator_tmp;
  13699. uc->obj.tmp_face_material.ator = &uc->ator_tmp;
  13700. uc->obj.tmp_face_smoothing.ator = &uc->ator_tmp;
  13701. uc->obj.tmp_face_group.ator = &uc->ator_tmp;
  13702. uc->obj.tmp_face_group_infos.ator = &uc->ator_tmp;
  13703. uc->obj.tmp_meshes.ator = &uc->ator_tmp;
  13704. uc->obj.tmp_props.ator = &uc->ator_tmp;
  13705. // .obj parsing does its own yield logic
  13706. uc->data_size += uc->yield_size;
  13707. uc->obj.object.data = ufbxi_empty_char;
  13708. uc->obj.group.data = ufbxi_empty_char;
  13709. ufbxi_map_init(&uc->obj.group_map, &uc->ator_tmp, ufbxi_map_cmp_const_char_ptr, NULL);
  13710. // Add a nameless root node with the root ID
  13711. {
  13712. ufbxi_element_info root_info = { uc->root_id };
  13713. root_info.name = ufbx_empty_string;
  13714. ufbx_node *root = ufbxi_push_element(uc, &root_info, ufbx_node, UFBX_ELEMENT_NODE);
  13715. ufbxi_check(root);
  13716. ufbxi_setup_root_node(uc, root);
  13717. ufbxi_check(ufbxi_push_copy(&uc->tmp_node_ids, uint32_t, 1, &root->element.element_id));
  13718. }
  13719. return 1;
  13720. }
  13721. static ufbxi_noinline void ufbxi_obj_free(ufbxi_context *uc)
  13722. {
  13723. if (!uc->obj.initialized) return;
  13724. ufbxi_nounroll for (size_t i = 0; i < UFBXI_OBJ_NUM_ATTRIBS_EXT; i++) {
  13725. ufbxi_buf_free(&uc->obj.tmp_vertices[i]);
  13726. ufbxi_buf_free(&uc->obj.tmp_indices[i]);
  13727. }
  13728. ufbxi_buf_free(&uc->obj.tmp_color_valid);
  13729. ufbxi_buf_free(&uc->obj.tmp_faces);
  13730. ufbxi_buf_free(&uc->obj.tmp_face_material);
  13731. ufbxi_buf_free(&uc->obj.tmp_face_smoothing);
  13732. ufbxi_buf_free(&uc->obj.tmp_face_group);
  13733. ufbxi_buf_free(&uc->obj.tmp_face_group_infos);
  13734. ufbxi_buf_free(&uc->obj.tmp_meshes);
  13735. ufbxi_buf_free(&uc->obj.tmp_props);
  13736. ufbxi_map_free(&uc->obj.group_map);
  13737. ufbxi_free(&uc->ator_tmp, ufbx_string, uc->obj.tokens, uc->obj.tokens_cap);
  13738. ufbxi_free(&uc->ator_tmp, ufbx_material*, uc->obj.tmp_materials, uc->obj.tmp_materials_cap);
  13739. }
  13740. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_read_line(ufbxi_context *uc)
  13741. {
  13742. ufbxi_dev_assert(!uc->obj.eof);
  13743. size_t offset = 0;
  13744. for (;;) {
  13745. const char *begin = ufbxi_add_ptr(uc->data, offset);
  13746. const char *end = begin ? (const char*)memchr(begin, '\n', uc->data_size - offset) : NULL;
  13747. if (!end) {
  13748. if (uc->eof) {
  13749. offset = uc->data_size;
  13750. uc->obj.eof = true;
  13751. break;
  13752. } else {
  13753. size_t new_cap = ufbxi_max_sz(1, uc->data_size * 2);
  13754. ufbxi_check(ufbxi_refill(uc, new_cap, false));
  13755. continue;
  13756. }
  13757. }
  13758. offset += ufbxi_to_size(end - begin) + 1;
  13759. // Handle line continuations
  13760. const char *esc = end;
  13761. if (esc > begin && esc[-1] == '\r') esc--;
  13762. if (esc > begin && esc[-1] == '\\') {
  13763. continue;
  13764. }
  13765. break;
  13766. }
  13767. size_t line_len = offset;
  13768. uc->obj.line.data = uc->data;
  13769. uc->obj.line.length = line_len;
  13770. uc->data += line_len;
  13771. uc->data_size -= line_len;
  13772. uc->obj.read_progress += line_len;
  13773. if (uc->obj.read_progress >= uc->progress_interval) {
  13774. ufbxi_check(ufbxi_report_progress(uc));
  13775. uc->obj.read_progress %= uc->progress_interval;
  13776. }
  13777. if (uc->obj.eof) {
  13778. char *new_data = ufbxi_push(&uc->tmp, char, line_len + 1);
  13779. ufbxi_check(new_data);
  13780. memcpy(new_data, uc->obj.line.data, line_len);
  13781. new_data[line_len] = '\n';
  13782. uc->obj.line.data = new_data;
  13783. uc->obj.line.length++;
  13784. }
  13785. return 1;
  13786. }
  13787. static ufbxi_noinline ufbx_string ufbxi_obj_span_token(ufbxi_context *uc, size_t start_token, size_t end_token)
  13788. {
  13789. ufbx_assert(start_token < uc->obj.num_tokens);
  13790. end_token = ufbxi_min_sz(end_token, uc->obj.num_tokens - 1);
  13791. ufbx_assert(start_token <= end_token);
  13792. ufbx_string start = uc->obj.tokens[start_token];
  13793. ufbx_string end = uc->obj.tokens[end_token];
  13794. size_t num_between = ufbxi_to_size(end.data - start.data);
  13795. ufbx_string result;
  13796. result.data = start.data;
  13797. result.length = num_between + end.length;
  13798. return result;
  13799. }
  13800. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_tokenize(ufbxi_context *uc)
  13801. {
  13802. const char *ptr = uc->obj.line.data, *end = ptr + uc->obj.line.length;
  13803. uc->obj.num_tokens = 0;
  13804. for (;;) {
  13805. char c;
  13806. // Skip whitespace
  13807. for (;;) {
  13808. c = *ptr;
  13809. if (c == ' ' || c == '\t' || c == '\r') {
  13810. ptr++;
  13811. continue;
  13812. }
  13813. // Treat line continuations as whitespace
  13814. if (c == '\\') {
  13815. const char *p = ptr + 1;
  13816. if (*p == '\r') p++;
  13817. if (*p == '\n' && p < end - 1) {
  13818. ptr = p + 1;
  13819. continue;
  13820. }
  13821. }
  13822. break;
  13823. }
  13824. c = *ptr;
  13825. if (c == '\n') break;
  13826. if (c == '#' && uc->obj.num_tokens > 0) break;
  13827. size_t index = uc->obj.num_tokens++;
  13828. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->obj.tokens, &uc->obj.tokens_cap, index + 1));
  13829. ufbx_string *tok = &uc->obj.tokens[index];
  13830. tok->data = ptr;
  13831. // Treat comment start as a single token
  13832. if (c == '#') {
  13833. ptr++;
  13834. tok->length = 1;
  13835. continue;
  13836. }
  13837. for (;;) {
  13838. c = *++ptr;
  13839. if (ufbxi_is_space(c)) {
  13840. break;
  13841. }
  13842. if (c == '\\') {
  13843. const char *p = ptr + 1;
  13844. if (*p == '\r') p++;
  13845. if (*p == '\n' && p < end - 1) {
  13846. break;
  13847. }
  13848. }
  13849. }
  13850. tok->length = ufbxi_to_size(ptr - tok->data);
  13851. }
  13852. return 1;
  13853. }
  13854. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_tokenize_line(ufbxi_context *uc)
  13855. {
  13856. ufbxi_check(ufbxi_obj_read_line(uc));
  13857. ufbxi_check(ufbxi_obj_tokenize(uc));
  13858. return 1;
  13859. }
  13860. static ufbxi_noinline int ufbxi_obj_parse_vertex(ufbxi_context *uc, ufbxi_obj_attrib attrib, size_t offset)
  13861. {
  13862. if (uc->opts.ignore_geometry) return 1;
  13863. ufbxi_buf *dst = &uc->obj.tmp_vertices[attrib];
  13864. size_t num_values = ufbxi_obj_attrib_stride[attrib];
  13865. uc->obj.vertex_count[attrib]++;
  13866. size_t read_values = num_values;
  13867. if (attrib == UFBXI_OBJ_ATTRIB_COLOR) {
  13868. if (offset + read_values > uc->obj.num_tokens) {
  13869. read_values = 3;
  13870. }
  13871. }
  13872. ufbxi_check(offset + read_values <= uc->obj.num_tokens);
  13873. uint32_t parse_flags = uc->double_parse_flags;
  13874. ufbx_real *vals = ufbxi_push_fast(dst, ufbx_real, num_values);
  13875. ufbxi_check(vals);
  13876. for (size_t i = 0; i < read_values; i++) {
  13877. ufbx_string str = uc->obj.tokens[offset + i];
  13878. char *end; // ufbxi_uninit
  13879. double val = ufbxi_parse_double(str.data, str.length, &end, parse_flags);
  13880. ufbxi_check(end == str.data + str.length);
  13881. vals[i] = (ufbx_real)val;
  13882. }
  13883. if (read_values < num_values) {
  13884. ufbx_assert(read_values + 1 == num_values);
  13885. ufbx_assert(attrib == UFBXI_OBJ_ATTRIB_COLOR);
  13886. vals[read_values] = 1.0f;
  13887. }
  13888. return 1;
  13889. }
  13890. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_parse_index(ufbxi_context *uc, ufbx_string *s, uint32_t attrib)
  13891. {
  13892. const char *ptr = s->data, *end = ptr + s->length;
  13893. bool negative = false;
  13894. if (*ptr == '-') {
  13895. negative = true;
  13896. ptr++;
  13897. }
  13898. // As .obj indices are never zero we can detect missing indices
  13899. // by simply not writing to it.
  13900. uint64_t index = 0;
  13901. for (; ptr != end; ptr++) {
  13902. char c = *ptr;
  13903. if (c >= '0' && c <= '9') {
  13904. ufbxi_check(index < UINT64_MAX / 10 - 10);
  13905. index = index * 10 + (uint64_t)(c - '0');
  13906. } else if (c == '/') {
  13907. ptr++;
  13908. break;
  13909. }
  13910. }
  13911. if (negative) {
  13912. size_t count = uc->obj.vertex_count[attrib];
  13913. index = index <= count ? count - index : UINT64_MAX;
  13914. } else {
  13915. // Corrects to zero based indices and wraps 0 to UINT64_MAX (missing)
  13916. index -= 1;
  13917. }
  13918. ufbxi_obj_fast_indices *fast_indices = &uc->obj.fast_indices[attrib];
  13919. if (fast_indices->num_left == 0) {
  13920. size_t num_push = 128;
  13921. uint64_t *dst = ufbxi_push(&uc->obj.tmp_indices[attrib], uint64_t, num_push);
  13922. ufbxi_check(dst);
  13923. uc->obj.fast_indices[attrib].indices = dst;
  13924. uc->obj.fast_indices[attrib].num_left = num_push;
  13925. }
  13926. *fast_indices->indices++ = index;
  13927. fast_indices->num_left--;
  13928. ufbxi_obj_mesh *mesh = uc->obj.mesh;
  13929. if (index != UINT64_MAX) {
  13930. ufbxi_obj_index_range *range = &mesh->vertex_range[attrib];
  13931. range->min_ix = ufbxi_min64(range->min_ix, index);
  13932. range->max_ix = ufbxi_max64(range->max_ix, index);
  13933. }
  13934. s->data = ptr;
  13935. s->length = ufbxi_to_size(end - ptr);
  13936. return 1;
  13937. }
  13938. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_parse_indices(ufbxi_context *uc, size_t token_begin, size_t num_tokens)
  13939. {
  13940. bool flush_mesh = false;
  13941. if (uc->obj.object_dirty) {
  13942. if (!uc->opts.obj_merge_objects) {
  13943. flush_mesh = true;
  13944. }
  13945. uc->obj.object_dirty = false;
  13946. }
  13947. if (uc->obj.group_dirty) {
  13948. if (((uc->obj.object.length == 0 || uc->opts.obj_merge_objects) && !uc->opts.obj_merge_groups) || uc->opts.obj_split_groups) {
  13949. flush_mesh = true;
  13950. }
  13951. uc->obj.group_dirty = false;
  13952. uc->obj.face_group_dirty = true;
  13953. }
  13954. if (!uc->obj.mesh || flush_mesh) {
  13955. ufbxi_check(ufbxi_obj_flush_mesh(uc));
  13956. ufbxi_check(ufbxi_obj_push_mesh(uc));
  13957. }
  13958. ufbxi_obj_mesh *mesh = uc->obj.mesh;
  13959. if (uc->obj.material_dirty) {
  13960. if (uc->obj.usemtl_fbx_id != 0) {
  13961. ufbxi_fbx_id_entry *entry = ufbxi_find_fbx_id(uc, uc->obj.usemtl_fbx_id);
  13962. ufbx_assert(entry);
  13963. if (mesh->usemtl_base == 0 || entry->user_id < mesh->usemtl_base) {
  13964. ufbxi_check(ufbxi_connect_oo(uc, uc->obj.usemtl_fbx_id, mesh->fbx_node_id));
  13965. uint32_t index = ++uc->obj.usemtl_index;
  13966. ufbxi_check(index < UINT32_MAX);
  13967. entry->user_id = index;
  13968. if (mesh->usemtl_base == 0) {
  13969. mesh->usemtl_base = index;
  13970. }
  13971. uc->obj.face_material = index - mesh->usemtl_base;
  13972. }
  13973. uc->obj.face_material = entry->user_id - mesh->usemtl_base;
  13974. }
  13975. }
  13976. // EARLY RETURN: Rest of the function should only be related to geometry!
  13977. if (uc->opts.ignore_geometry) return 1;
  13978. if (num_tokens == 0 && !uc->opts.allow_empty_faces) {
  13979. ufbxi_check(ufbxi_warnf(UFBX_WARNING_EMPTY_FACE_REMOVED, "Empty face has been removed"));
  13980. return 1;
  13981. }
  13982. if (uc->obj.face_group_dirty) {
  13983. ufbx_string name = ufbx_empty_string;
  13984. if (uc->obj.group.length > 0 && (uc->obj.object.length > 0 || uc->opts.obj_merge_groups) && !uc->opts.obj_split_groups) {
  13985. name = uc->obj.group;
  13986. }
  13987. uint32_t hash = ufbxi_hash_ptr(name.data);
  13988. ufbxi_obj_group_entry *entry = ufbxi_map_find(&uc->obj.group_map, ufbxi_obj_group_entry, hash, &name.data);
  13989. if (!entry) {
  13990. entry = ufbxi_map_insert(&uc->obj.group_map, ufbxi_obj_group_entry, hash, &name.data);
  13991. ufbxi_check(entry);
  13992. entry->name = name.data;
  13993. entry->mesh_id = 0;
  13994. entry->local_id = 0;
  13995. }
  13996. uint32_t mesh_id = mesh->fbx_mesh->element_id;
  13997. if (entry->mesh_id != mesh_id) {
  13998. uint32_t id = mesh->num_groups++;
  13999. entry->mesh_id = mesh_id;
  14000. entry->local_id = id;
  14001. ufbx_face_group *group = ufbxi_push_zero(&uc->obj.tmp_face_group_infos, ufbx_face_group, 1);
  14002. ufbxi_check(group);
  14003. group->id = 0;
  14004. group->name = name;
  14005. }
  14006. uc->obj.face_group = entry->local_id;
  14007. if (!uc->obj.has_face_group) {
  14008. uc->obj.has_face_group = true;
  14009. ufbxi_check(ufbxi_push_zero(&uc->obj.tmp_face_group, uint32_t, uc->obj.tmp_faces.num_items));
  14010. }
  14011. uc->obj.face_group_dirty = false;
  14012. }
  14013. size_t num_indices = num_tokens;
  14014. ufbxi_check(UINT32_MAX - mesh->num_indices >= num_indices);
  14015. ufbx_face *face = ufbxi_push_fast(&uc->obj.tmp_faces, ufbx_face, 1);
  14016. ufbxi_check(face);
  14017. face->index_begin = (uint32_t)mesh->num_indices;
  14018. face->num_indices = (uint32_t)num_indices;
  14019. mesh->num_faces++;
  14020. mesh->num_indices += num_indices;
  14021. uint32_t *p_face_mat = ufbxi_push_fast(&uc->obj.tmp_face_material, uint32_t, 1);
  14022. ufbxi_check(p_face_mat);
  14023. *p_face_mat = uc->obj.face_material;
  14024. if (uc->obj.has_face_smoothing) {
  14025. bool *p_face_smooth = ufbxi_push_fast(&uc->obj.tmp_face_smoothing, bool, 1);
  14026. ufbxi_check(p_face_smooth);
  14027. *p_face_smooth = uc->obj.face_smoothing;
  14028. }
  14029. if (uc->obj.has_face_group) {
  14030. uint32_t *p_face_group = ufbxi_push_fast(&uc->obj.tmp_face_group, uint32_t, 1);
  14031. ufbxi_check(p_face_group);
  14032. *p_face_group = uc->obj.face_group;
  14033. }
  14034. for (size_t ix = 0; ix < num_indices; ix++) {
  14035. ufbx_string tok = uc->obj.tokens[token_begin + ix];
  14036. for (uint32_t attrib = 0; attrib < UFBXI_OBJ_NUM_ATTRIBS; attrib++) {
  14037. ufbxi_check(ufbxi_obj_parse_index(uc, &tok, attrib));
  14038. }
  14039. }
  14040. return 1;
  14041. }
  14042. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_parse_multi_indices(ufbxi_context *uc, size_t window)
  14043. {
  14044. for (size_t begin = 1; begin + window <= uc->obj.num_tokens; begin++) {
  14045. ufbxi_check(ufbxi_obj_parse_indices(uc, begin, window));
  14046. }
  14047. return 1;
  14048. }
  14049. static ufbxi_noinline uint32_t ufbxi_parse_hex(const char *digits, size_t length)
  14050. {
  14051. uint32_t value = 0;
  14052. for (size_t i = 0; i < length; i++) {
  14053. char c = digits[i];
  14054. uint32_t v = 0;
  14055. if (c >= '0' && c <= '9') {
  14056. v = (uint32_t)(c - '0');
  14057. } else if (c >= 'A' && c <= 'F') {
  14058. v = (uint32_t)(c - 'A') + 10;
  14059. } else if (c >= 'a' && c <= 'f') {
  14060. v = (uint32_t)(c - 'a') + 10;
  14061. }
  14062. value = (value << 4) | v;
  14063. }
  14064. return value;
  14065. }
  14066. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_parse_comment(ufbxi_context *uc)
  14067. {
  14068. if (uc->obj.num_tokens >= 3 && ufbxi_str_equal(uc->obj.tokens[1], ufbxi_str_c("MRGB"))) {
  14069. size_t num_color = uc->obj.vertex_count[UFBXI_OBJ_ATTRIB_COLOR];
  14070. // Pop standard vertex colors and replace them with MRGB colors
  14071. if (num_color > uc->obj.mrgb_vertex_count) {
  14072. size_t num_pop = num_color - uc->obj.mrgb_vertex_count;
  14073. ufbxi_pop(&uc->obj.tmp_color_valid, bool, num_pop, NULL);
  14074. ufbxi_pop(&uc->obj.tmp_vertices[UFBXI_OBJ_ATTRIB_COLOR], ufbx_real, num_pop * 4, NULL);
  14075. uc->obj.vertex_count[UFBXI_OBJ_ATTRIB_COLOR] -= num_pop;
  14076. }
  14077. ufbx_string mrgb = uc->obj.tokens[2];
  14078. for (size_t i = 0; i + 8 <= mrgb.length; i += 8) {
  14079. ufbx_real *p_rgba = ufbxi_push(&uc->obj.tmp_vertices[UFBXI_OBJ_ATTRIB_COLOR], ufbx_real, 4);
  14080. bool *p_valid = ufbxi_push(&uc->obj.tmp_color_valid, bool, 1);
  14081. ufbxi_check(p_rgba && p_valid);
  14082. *p_valid = true;
  14083. uint32_t hex = ufbxi_parse_hex(mrgb.data + i, 8);
  14084. p_rgba[0] = (ufbx_real)((hex >> 16u) & 0xff) / 255.0f;
  14085. p_rgba[1] = (ufbx_real)((hex >> 8u) & 0xff) / 255.0f;
  14086. p_rgba[2] = (ufbx_real)((hex >> 0u) & 0xff) / 255.0f;
  14087. p_rgba[3] = (ufbx_real)((hex >> 24u) & 0xff) / 255.0f;
  14088. }
  14089. uc->obj.has_vertex_color = true;
  14090. }
  14091. if (!uc->opts.disable_quirks) {
  14092. if (ufbxi_match(&uc->obj.line, "\\s*#\\s*File exported by ZBrush.*")) {
  14093. if (!uc->obj.mesh) {
  14094. uc->opts.obj_merge_groups = true;
  14095. }
  14096. }
  14097. }
  14098. return 1;
  14099. }
  14100. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_parse_material(ufbxi_context *uc)
  14101. {
  14102. ufbxi_check(uc->obj.num_tokens >= 2);
  14103. ufbx_string name = ufbxi_obj_span_token(uc, 1, SIZE_MAX);
  14104. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &name, false));
  14105. uint64_t fbx_id = ufbxi_synthetic_id_from_string(name.data);
  14106. ufbxi_fbx_id_entry *entry = ufbxi_find_fbx_id(uc, fbx_id);
  14107. uc->obj.usemtl_fbx_id = fbx_id;
  14108. uc->obj.usemtl_name = name;
  14109. if (!entry) {
  14110. ufbxi_element_info info = { 0 };
  14111. info.fbx_id = fbx_id;
  14112. info.name = name;
  14113. ufbx_material *material = ufbxi_push_element(uc, &info, ufbx_material, UFBX_ELEMENT_MATERIAL);
  14114. ufbxi_check(material);
  14115. material->shader_type = UFBX_SHADER_WAVEFRONT_MTL;
  14116. material->shading_model_name.data = ufbxi_empty_char;
  14117. material->shader_prop_prefix.data = ufbxi_empty_char;
  14118. size_t id = material->element_id;
  14119. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->obj.tmp_materials, &uc->obj.tmp_materials_cap, id + 1));
  14120. uc->obj.tmp_materials[id] = material;
  14121. }
  14122. uc->obj.material_dirty = true;
  14123. return 1;
  14124. }
  14125. #define ufbxi_obj_cmd1(a) ((uint32_t)(a)<<24u)
  14126. #define ufbxi_obj_cmd2(a,b) ((uint32_t)(a)<<24u | (uint32_t)(b)<<16)
  14127. #define ufbxi_obj_cmd3(a,b,c) ((uint32_t)(a)<<24u | (uint32_t)(b)<<16 | (uint32_t)(c)<<8u)
  14128. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_pop_vertices(ufbxi_context *uc, ufbx_real_list *dst, uint32_t attrib, uint64_t min_index)
  14129. {
  14130. size_t stride = ufbxi_obj_attrib_stride[attrib];
  14131. ufbxi_check(min_index < uc->obj.tmp_vertices[attrib].num_items / stride);
  14132. size_t count = uc->obj.tmp_vertices[attrib].num_items - (size_t)min_index * stride;
  14133. ufbx_real *data = ufbxi_push(&uc->result, ufbx_real, count + 4);
  14134. ufbxi_check(data);
  14135. data[0] = 0.0f;
  14136. data[1] = 0.0f;
  14137. data[2] = 0.0f;
  14138. data[3] = 0.0f;
  14139. data += 4;
  14140. ufbxi_pop(&uc->obj.tmp_vertices[attrib], ufbx_real, count, data);
  14141. dst->data = data;
  14142. dst->count = count;
  14143. return 1;
  14144. }
  14145. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_setup_attrib(ufbxi_context *uc, ufbxi_obj_mesh *mesh, uint64_t *tmp_indices,
  14146. ufbx_vertex_attrib *dst, const ufbx_real_list *p_data, uint32_t attrib, bool non_disjoint, bool required)
  14147. {
  14148. ufbx_real_list data = *p_data;
  14149. size_t num_indices = mesh->num_indices;
  14150. size_t stride = ufbxi_obj_attrib_stride[attrib];
  14151. size_t num_values = data.count / stride;
  14152. uint64_t mesh_min_ix = mesh->vertex_range[attrib].min_ix;
  14153. if (num_indices == 0 || num_values == 0 || mesh_min_ix == UINT64_MAX) {
  14154. ufbxi_check(num_indices == 0 || !required);
  14155. // Pop indices without copying if the attribute is not used
  14156. ufbxi_pop(&uc->obj.tmp_indices[attrib], uint64_t, num_indices, NULL);
  14157. return 1;
  14158. }
  14159. uint64_t min_index = non_disjoint ? 0 : mesh_min_ix;
  14160. ufbxi_pop(&uc->obj.tmp_indices[attrib], uint64_t, num_indices, tmp_indices);
  14161. uint32_t *dst_indices = ufbxi_push(&uc->result, uint32_t, num_indices);
  14162. ufbxi_check(dst_indices);
  14163. dst->exists = true;
  14164. dst->values.data = data.data;
  14165. dst->values.count = num_values;
  14166. dst->indices.data = dst_indices;
  14167. dst->indices.count = num_indices;
  14168. ufbxi_nounroll for (size_t i = 0; i < num_indices; i++) {
  14169. uint64_t ix = tmp_indices[i];
  14170. if (ix != UINT64_MAX) {
  14171. ix -= min_index;
  14172. ufbxi_check(ix < UINT32_MAX);
  14173. }
  14174. if (ix < num_values) {
  14175. dst_indices[i] = (uint32_t)ix;
  14176. } else {
  14177. ufbxi_check(ufbxi_fix_index(uc, &dst_indices[i], (uint32_t)ix, num_values));
  14178. }
  14179. }
  14180. return 1;
  14181. }
  14182. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_pad_colors(ufbxi_context *uc, size_t num_vertices)
  14183. {
  14184. if (uc->opts.ignore_geometry) return 1;
  14185. size_t num_colors = uc->obj.vertex_count[UFBXI_OBJ_ATTRIB_COLOR];
  14186. if (num_vertices > num_colors) {
  14187. size_t num_pad = num_vertices - num_colors;
  14188. ufbxi_check(ufbxi_push_zero(&uc->obj.tmp_vertices[UFBXI_OBJ_ATTRIB_COLOR], ufbx_real, num_pad * 4));
  14189. ufbxi_check(ufbxi_push_zero(&uc->obj.tmp_color_valid, bool, num_pad));
  14190. uc->obj.vertex_count[UFBXI_OBJ_ATTRIB_COLOR] += num_pad;
  14191. }
  14192. return 1;
  14193. }
  14194. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_pop_meshes(ufbxi_context *uc)
  14195. {
  14196. size_t num_meshes = uc->obj.tmp_meshes.num_items;
  14197. ufbxi_obj_mesh *meshes = ufbxi_push_pop(&uc->tmp, &uc->obj.tmp_meshes, ufbxi_obj_mesh, num_meshes);
  14198. ufbxi_check(meshes);
  14199. if (uc->obj.has_vertex_color) {
  14200. ufbxi_check(ufbxi_obj_pad_colors(uc, uc->obj.vertex_count[UFBXI_OBJ_ATTRIB_POSITION]));
  14201. }
  14202. // Pop unused fast indices
  14203. for (size_t i = 0; i < UFBXI_OBJ_NUM_ATTRIBS; i++) {
  14204. ufbxi_pop(&uc->obj.tmp_indices[i], uint64_t, uc->obj.fast_indices[i].num_left, NULL);
  14205. }
  14206. // Check if the file has disjoint vertices
  14207. bool non_disjoint[UFBXI_OBJ_NUM_ATTRIBS] = { 0 };
  14208. uint64_t next_min[UFBXI_OBJ_NUM_ATTRIBS] = { 0 };
  14209. ufbx_real_list vertices[UFBXI_OBJ_NUM_ATTRIBS_EXT] = { 0 };
  14210. bool *color_valid = NULL;
  14211. size_t max_indices = 0;
  14212. for (size_t i = 0; i < num_meshes; i++) {
  14213. ufbxi_obj_mesh *mesh = &meshes[i];
  14214. max_indices = ufbxi_max_sz(max_indices, mesh->num_indices);
  14215. ufbxi_nounroll for (uint32_t attrib = 0; attrib < UFBXI_OBJ_NUM_ATTRIBS; attrib++) {
  14216. ufbxi_obj_index_range range = mesh->vertex_range[attrib];
  14217. if (range.min_ix > range.max_ix) continue;
  14218. if (range.min_ix < next_min[attrib]) {
  14219. non_disjoint[attrib] = true;
  14220. }
  14221. next_min[attrib] = range.max_ix + 1;
  14222. }
  14223. }
  14224. uint64_t *tmp_indices = ufbxi_push(&uc->tmp, uint64_t, max_indices);
  14225. ufbxi_check(tmp_indices);
  14226. ufbxi_nounroll for (uint32_t attrib = 0; attrib < UFBXI_OBJ_NUM_ATTRIBS; attrib++) {
  14227. if (!non_disjoint[attrib]) continue;
  14228. ufbxi_check(ufbxi_obj_pop_vertices(uc, &vertices[attrib], attrib, 0));
  14229. }
  14230. if (uc->obj.has_vertex_color && non_disjoint[UFBXI_OBJ_ATTRIB_POSITION]) {
  14231. ufbxi_check(ufbxi_obj_pop_vertices(uc, &vertices[UFBXI_OBJ_ATTRIB_COLOR], UFBXI_OBJ_ATTRIB_COLOR, 0));
  14232. color_valid = ufbxi_push_pop(&uc->tmp, &uc->obj.tmp_color_valid, bool, vertices[UFBXI_OBJ_ATTRIB_COLOR].count / 4);
  14233. ufbxi_check(color_valid);
  14234. }
  14235. for (size_t i = num_meshes; i > 0; i--) {
  14236. ufbxi_obj_mesh *mesh = &meshes[i - 1];
  14237. ufbx_mesh *fbx_mesh = mesh->fbx_mesh;
  14238. size_t num_faces = mesh->num_faces;
  14239. if (!uc->opts.ignore_geometry) {
  14240. ufbxi_nounroll for (uint32_t attrib = 0; attrib < UFBXI_OBJ_NUM_ATTRIBS; attrib++) {
  14241. if (non_disjoint[attrib]) continue;
  14242. uint64_t min_ix = mesh->vertex_range[attrib].min_ix;
  14243. if (min_ix < UINT64_MAX) {
  14244. ufbxi_check(ufbxi_obj_pop_vertices(uc, &vertices[attrib], attrib, min_ix));
  14245. }
  14246. }
  14247. if (uc->obj.has_vertex_color && !non_disjoint[UFBXI_OBJ_ATTRIB_POSITION]) {
  14248. uint64_t min_ix = mesh->vertex_range[UFBXI_OBJ_ATTRIB_POSITION].min_ix;
  14249. ufbxi_check(min_ix < UINT64_MAX);
  14250. ufbxi_check(ufbxi_obj_pop_vertices(uc, &vertices[UFBXI_OBJ_ATTRIB_COLOR], UFBXI_OBJ_ATTRIB_COLOR, min_ix));
  14251. color_valid = ufbxi_push_pop(&uc->tmp, &uc->obj.tmp_color_valid, bool, vertices[UFBXI_OBJ_ATTRIB_COLOR].count / 4);
  14252. ufbxi_check(color_valid);
  14253. }
  14254. fbx_mesh->faces.count = num_faces;
  14255. fbx_mesh->face_material.count = num_faces;
  14256. fbx_mesh->faces.data = ufbxi_push_pop(&uc->result, &uc->obj.tmp_faces, ufbx_face, num_faces);
  14257. fbx_mesh->face_material.data = ufbxi_push_pop(&uc->result, &uc->obj.tmp_face_material, uint32_t, num_faces);
  14258. ufbxi_check(fbx_mesh->faces.data);
  14259. ufbxi_check(fbx_mesh->face_material.data);
  14260. if (uc->obj.has_face_smoothing) {
  14261. fbx_mesh->face_smoothing.count = num_faces;
  14262. fbx_mesh->face_smoothing.data = ufbxi_push_pop(&uc->result, &uc->obj.tmp_face_smoothing, bool, num_faces);
  14263. ufbxi_check(fbx_mesh->face_smoothing.data);
  14264. }
  14265. if (uc->obj.has_face_group) {
  14266. if (mesh->num_groups > 1) {
  14267. fbx_mesh->face_group.count = num_faces;
  14268. fbx_mesh->face_group.data = ufbxi_push_pop(&uc->result, &uc->obj.tmp_face_group, uint32_t, num_faces);
  14269. ufbxi_check(fbx_mesh->face_group.data);
  14270. } else {
  14271. ufbxi_pop(&uc->obj.tmp_face_group, uint32_t, num_faces, NULL);
  14272. }
  14273. }
  14274. ufbxi_check(ufbxi_obj_setup_attrib(uc, mesh, tmp_indices, (ufbx_vertex_attrib*)&fbx_mesh->vertex_position,
  14275. &vertices[UFBXI_OBJ_ATTRIB_POSITION], UFBXI_OBJ_ATTRIB_POSITION, non_disjoint[UFBXI_OBJ_ATTRIB_POSITION], true));
  14276. ufbxi_check(ufbxi_obj_setup_attrib(uc, mesh, tmp_indices, (ufbx_vertex_attrib*)&fbx_mesh->vertex_uv,
  14277. &vertices[UFBXI_OBJ_ATTRIB_UV], UFBXI_OBJ_ATTRIB_UV, non_disjoint[UFBXI_OBJ_ATTRIB_UV], false));
  14278. ufbxi_check(ufbxi_obj_setup_attrib(uc, mesh, tmp_indices, (ufbx_vertex_attrib*)&fbx_mesh->vertex_normal,
  14279. &vertices[UFBXI_OBJ_ATTRIB_NORMAL], UFBXI_OBJ_ATTRIB_NORMAL, non_disjoint[UFBXI_OBJ_ATTRIB_NORMAL], false));
  14280. if (uc->obj.has_vertex_color) {
  14281. ufbx_assert(color_valid);
  14282. bool has_color = false;
  14283. bool all_valid = true;
  14284. size_t max_index = fbx_mesh->vertex_position.values.count;
  14285. ufbxi_for_list(uint32_t, p_ix, fbx_mesh->vertex_position.indices) {
  14286. if (*p_ix < max_index) {
  14287. if (color_valid[*p_ix]) {
  14288. has_color = true;
  14289. } else {
  14290. all_valid = false;
  14291. }
  14292. }
  14293. }
  14294. if (has_color) {
  14295. fbx_mesh->vertex_color.exists = true;
  14296. fbx_mesh->vertex_color.values.data = (ufbx_vec4*)vertices[UFBXI_OBJ_ATTRIB_COLOR].data;
  14297. fbx_mesh->vertex_color.values.count = vertices[UFBXI_OBJ_ATTRIB_COLOR].count / 4;
  14298. fbx_mesh->vertex_color.indices = fbx_mesh->vertex_position.indices;
  14299. fbx_mesh->vertex_color.unique_per_vertex = true;
  14300. if (!all_valid) {
  14301. uint32_t *indices = fbx_mesh->vertex_color.indices.data;
  14302. indices = ufbxi_push_copy(&uc->result, uint32_t, mesh->num_indices, indices);
  14303. ufbxi_check(indices);
  14304. size_t num_values = fbx_mesh->vertex_color.values.count;
  14305. ufbxi_for(uint32_t, p_ix, indices, mesh->num_indices) {
  14306. if (*p_ix >= num_values || !color_valid[*p_ix]) {
  14307. ufbxi_check(ufbxi_fix_index(uc, p_ix, *p_ix, num_values));
  14308. }
  14309. }
  14310. fbx_mesh->vertex_color.indices.data = indices;
  14311. }
  14312. }
  14313. }
  14314. }
  14315. ufbxi_check(ufbxi_finalize_mesh(&uc->result, &uc->error, fbx_mesh));
  14316. if (uc->retain_mesh_parts) {
  14317. fbx_mesh->face_group_parts.count = mesh->num_groups;
  14318. fbx_mesh->face_group_parts.data = ufbxi_push_zero(&uc->result, ufbx_mesh_part, mesh->num_groups);
  14319. ufbxi_check(fbx_mesh->face_group_parts.data);
  14320. }
  14321. if (mesh->num_groups > 1) {
  14322. ufbxi_check(ufbxi_update_face_groups(&uc->result, &uc->error, fbx_mesh, false));
  14323. } else if (mesh->num_groups == 1) {
  14324. fbx_mesh->face_group.data = (uint32_t*)ufbxi_sentinel_index_zero;
  14325. fbx_mesh->face_group.count = num_faces;
  14326. // NOTE: Consecutive and zero indices are always allocated so we can skip doing it here,
  14327. // see HACK(consecutiv-faces)..
  14328. if (fbx_mesh->face_group_parts.count > 0) {
  14329. ufbx_mesh_part *part = &fbx_mesh->face_group_parts.data[0];
  14330. part->num_faces = fbx_mesh->num_faces;
  14331. part->num_faces = num_faces;
  14332. part->num_empty_faces = fbx_mesh->num_empty_faces;
  14333. part->num_point_faces = fbx_mesh->num_point_faces;
  14334. part->num_line_faces = fbx_mesh->num_line_faces;
  14335. part->num_triangles = fbx_mesh->num_triangles;
  14336. part->face_indices.data = (uint32_t*)ufbxi_sentinel_index_consecutive;
  14337. part->face_indices.count = num_faces;
  14338. }
  14339. }
  14340. // HACK(consecutive-faces): Prepare for finalize to re-use a consecutive/zero
  14341. // index buffer for face materials..
  14342. uc->max_zero_indices = ufbxi_max_sz(uc->max_zero_indices, num_faces);
  14343. uc->max_consecutive_indices = ufbxi_max_sz(uc->max_consecutive_indices, num_faces);
  14344. }
  14345. return 1;
  14346. }
  14347. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_parse_file(ufbxi_context *uc)
  14348. {
  14349. while (!uc->obj.eof) {
  14350. ufbxi_check(ufbxi_obj_tokenize_line(uc));
  14351. size_t num_tokens = uc->obj.num_tokens;
  14352. if (num_tokens == 0) continue;
  14353. ufbx_string cmd = uc->obj.tokens[0];
  14354. uint32_t key = ufbxi_get_name_key(cmd.data, cmd.length);
  14355. if (key == ufbxi_obj_cmd1('v')) {
  14356. ufbxi_check(ufbxi_obj_parse_vertex(uc, UFBXI_OBJ_ATTRIB_POSITION, 1));
  14357. if (num_tokens >= 7) {
  14358. size_t num_vertices = uc->obj.vertex_count[UFBXI_OBJ_ATTRIB_POSITION];
  14359. uc->obj.has_vertex_color = true;
  14360. ufbxi_check(ufbxi_obj_pad_colors(uc, num_vertices - 1));
  14361. if (uc->obj.vertex_count[UFBXI_OBJ_ATTRIB_COLOR] < num_vertices) {
  14362. ufbx_assert(uc->obj.vertex_count[UFBXI_OBJ_ATTRIB_COLOR] == num_vertices - 1);
  14363. ufbxi_check(ufbxi_obj_parse_vertex(uc, UFBXI_OBJ_ATTRIB_COLOR, 4));
  14364. bool *valid = ufbxi_push(&uc->obj.tmp_color_valid, bool, 1);
  14365. ufbxi_check(valid);
  14366. *valid = true;
  14367. }
  14368. }
  14369. } else if (key == ufbxi_obj_cmd2('v','t')) {
  14370. ufbxi_check(ufbxi_obj_parse_vertex(uc, UFBXI_OBJ_ATTRIB_UV, 1));
  14371. } else if (key == ufbxi_obj_cmd2('v','n')) {
  14372. ufbxi_check(ufbxi_obj_parse_vertex(uc, UFBXI_OBJ_ATTRIB_NORMAL, 1));
  14373. } else if (key == ufbxi_obj_cmd1('f')) {
  14374. ufbxi_check(ufbxi_obj_parse_indices(uc, 1, uc->obj.num_tokens - 1));
  14375. } else if (key == ufbxi_obj_cmd1('p')) {
  14376. ufbxi_check(ufbxi_obj_parse_multi_indices(uc, 1));
  14377. } else if (key == ufbxi_obj_cmd1('l')) {
  14378. ufbxi_check(ufbxi_obj_parse_multi_indices(uc, 2));
  14379. } else if (key == ufbxi_obj_cmd1('s')) {
  14380. if (num_tokens >= 2) {
  14381. uc->obj.has_face_smoothing = true;
  14382. uc->obj.face_smoothing = !ufbxi_str_equal(uc->obj.tokens[1], ufbxi_str_c("off"));
  14383. // Fill in previously missed face smoothing data
  14384. if (uc->obj.tmp_face_smoothing.num_items == 0 && uc->obj.tmp_faces.num_items > 0) {
  14385. ufbxi_check(ufbxi_push_zero(&uc->obj.tmp_face_smoothing, bool, uc->obj.tmp_faces.num_items));
  14386. }
  14387. }
  14388. } else if (key == ufbxi_obj_cmd1('o')) {
  14389. if (num_tokens >= 2) {
  14390. uc->obj.object = ufbxi_obj_span_token(uc, 1, SIZE_MAX);
  14391. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &uc->obj.object, false));
  14392. uc->obj.object_dirty = true;
  14393. }
  14394. } else if (key == ufbxi_obj_cmd1('g')) {
  14395. if (num_tokens >= 2) {
  14396. uc->obj.group = ufbxi_obj_span_token(uc, 1, SIZE_MAX);
  14397. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &uc->obj.group, false));
  14398. uc->obj.group_dirty = true;
  14399. } else {
  14400. uc->obj.group = ufbx_empty_string;
  14401. uc->obj.group_dirty = true;
  14402. }
  14403. } else if (key == ufbxi_obj_cmd1('#')) {
  14404. ufbxi_check(ufbxi_obj_parse_comment(uc));
  14405. } else if (ufbxi_str_equal(cmd, ufbxi_str_c("mtllib"))) {
  14406. ufbxi_check(uc->obj.num_tokens >= 2);
  14407. ufbx_string lib = ufbxi_obj_span_token(uc, 1, SIZE_MAX);
  14408. lib.data = ufbxi_push_copy(&uc->tmp, char, lib.length + 1, lib.data);
  14409. ufbxi_check(lib.data);
  14410. uc->obj.mtllib_relative_path.data = lib.data;
  14411. uc->obj.mtllib_relative_path.size = lib.length;
  14412. } else if (ufbxi_str_equal(cmd, ufbxi_str_c("usemtl"))) {
  14413. ufbxi_check(ufbxi_obj_parse_material(uc));
  14414. } else {
  14415. ufbxi_check(ufbxi_warnf(UFBX_WARNING_UNKNOWN_OBJ_DIRECTIVE, "Unknown .obj directive, skipped line"));
  14416. }
  14417. }
  14418. ufbxi_check(ufbxi_obj_flush_mesh(uc));
  14419. ufbxi_check(ufbxi_obj_pop_meshes(uc));
  14420. return 1;
  14421. }
  14422. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_flush_material(ufbxi_context *uc)
  14423. {
  14424. if (uc->obj.usemtl_fbx_id == 0) return 1;
  14425. ufbxi_fbx_id_entry *entry = ufbxi_find_fbx_id(uc, uc->obj.usemtl_fbx_id);
  14426. ufbx_assert(entry);
  14427. ufbx_material *material = uc->obj.tmp_materials[entry->element_id];
  14428. size_t num_props = uc->obj.tmp_props.num_items;
  14429. ufbxi_check(ufbxi_obj_pop_props(uc, &material->props.props, num_props));
  14430. return 1;
  14431. }
  14432. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_parse_prop(ufbxi_context *uc, ufbx_string name, size_t start, bool include_rest, size_t *p_next)
  14433. {
  14434. if (start >= uc->obj.num_tokens) {
  14435. if (p_next) {
  14436. *p_next = start;
  14437. }
  14438. return 1;
  14439. }
  14440. ufbx_prop *prop = ufbxi_push_zero(&uc->obj.tmp_props, ufbx_prop, 1);
  14441. ufbxi_check(prop);
  14442. prop->name = name;
  14443. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &prop->name, false));
  14444. uint32_t flags = UFBX_PROP_FLAG_VALUE_STR;
  14445. size_t num_reals = 0;
  14446. for (; num_reals < 4; num_reals++) {
  14447. if (start + num_reals >= uc->obj.num_tokens) break;
  14448. ufbx_string tok = uc->obj.tokens[start + num_reals];
  14449. char *end; // ufbxi_uninit
  14450. double val = ufbxi_parse_double(tok.data, tok.length, &end, uc->double_parse_flags);
  14451. if (end != tok.data + tok.length) break;
  14452. prop->value_real_arr[num_reals] = (ufbx_real)val;
  14453. if (num_reals == 0) {
  14454. prop->value_int = ufbxi_f64_to_i64(val);
  14455. flags |= UFBX_PROP_FLAG_VALUE_INT;
  14456. }
  14457. }
  14458. size_t num_args = 0;
  14459. if (!include_rest) {
  14460. for (; start + num_args < uc->obj.num_tokens - 1; num_args++) {
  14461. if (ufbxi_match(&uc->obj.tokens[start + num_args], "-[A-Za-z][\\-A-Za-z0-9_]*")) break;
  14462. }
  14463. }
  14464. if (num_args > 0 || include_rest) {
  14465. ufbx_string span = ufbxi_obj_span_token(uc, start, include_rest ? SIZE_MAX : start + num_args - 1);
  14466. prop->value_str = span;
  14467. prop->value_blob.data = span.data;
  14468. prop->value_blob.size = span.length;
  14469. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &prop->value_str, false));
  14470. ufbxi_check(ufbxi_push_string_place_blob(&uc->string_pool, &prop->value_blob, true));
  14471. } else {
  14472. prop->value_str.data = ufbxi_empty_char;
  14473. }
  14474. if (num_reals > 0) {
  14475. flags = (uint32_t)UFBX_PROP_FLAG_VALUE_REAL << (num_reals - 1);
  14476. } else {
  14477. if (!strcmp(prop->value_str.data, "on")) {
  14478. prop->value_int = 1;
  14479. prop->value_real = 1.0f;
  14480. flags |= UFBX_PROP_FLAG_VALUE_INT;
  14481. } else if (!strcmp(prop->value_str.data, "off")) {
  14482. prop->value_int = 0;
  14483. prop->value_real = 0.0f;
  14484. flags |= UFBX_PROP_FLAG_VALUE_INT;
  14485. }
  14486. }
  14487. prop->flags = (ufbx_prop_flags)flags;
  14488. if (p_next) {
  14489. *p_next = start + num_args;
  14490. }
  14491. return 1;
  14492. }
  14493. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_parse_mtl_map(ufbxi_context *uc, size_t prefix_len)
  14494. {
  14495. if (uc->obj.num_tokens < 2) return 1;
  14496. size_t num_props = 1;
  14497. ufbxi_check(ufbxi_obj_parse_prop(uc, ufbxi_str_c("obj|args"), 1, true, NULL));
  14498. size_t start = 1;
  14499. for (; start + 1 < uc->obj.num_tokens; ) {
  14500. ufbx_string tok = uc->obj.tokens[start];
  14501. if (ufbxi_match(&tok, "-[A-Za-z][\\-A-Za-z0-9_]*")) {
  14502. tok.data += 1;
  14503. tok.length -= 1;
  14504. ufbxi_check(ufbxi_obj_parse_prop(uc, tok, start + 1, false, &start));
  14505. num_props++;
  14506. } else {
  14507. break;
  14508. }
  14509. }
  14510. ufbx_string tex_str = ufbxi_obj_span_token(uc, start, SIZE_MAX);
  14511. ufbx_blob tex_raw = { tex_str.data, tex_str.length };
  14512. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &tex_str, false));
  14513. ufbxi_check(ufbxi_push_string_place_blob(&uc->string_pool, &tex_raw, true));
  14514. uint64_t fbx_id = 0;
  14515. ufbx_texture *texture = ufbxi_push_synthetic_element(uc, &fbx_id, NULL, "", ufbx_texture, UFBX_ELEMENT_TEXTURE);
  14516. ufbxi_check(texture);
  14517. texture->filename.data = ufbxi_empty_char;
  14518. texture->absolute_filename.data = ufbxi_empty_char;
  14519. texture->uv_set.data = ufbxi_empty_char;
  14520. texture->relative_filename = tex_str;
  14521. texture->raw_relative_filename = tex_raw;
  14522. ufbxi_check(ufbxi_obj_pop_props(uc, &texture->props.props, num_props));
  14523. ufbx_string prop = uc->obj.tokens[0];
  14524. ufbx_assert(prop.length >= prefix_len);
  14525. prop.data += prefix_len;
  14526. prop.length -= prefix_len;
  14527. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &prop, false));
  14528. if (uc->obj.usemtl_fbx_id != 0) {
  14529. ufbxi_check(ufbxi_connect_op(uc, fbx_id, uc->obj.usemtl_fbx_id, prop));
  14530. }
  14531. return 1;
  14532. }
  14533. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_parse_mtl(ufbxi_context *uc)
  14534. {
  14535. uc->obj.mesh = NULL;
  14536. uc->obj.usemtl_fbx_id = 0;
  14537. while (!uc->obj.eof) {
  14538. ufbxi_check(ufbxi_obj_tokenize_line(uc));
  14539. size_t num_tokens = uc->obj.num_tokens;
  14540. if (num_tokens == 0) continue;
  14541. ufbx_string cmd = uc->obj.tokens[0];
  14542. if (ufbxi_str_equal(cmd, ufbxi_str_c("newmtl"))) {
  14543. // HACK: Reuse mesh material parsing
  14544. ufbxi_check(ufbxi_obj_flush_material(uc));
  14545. ufbxi_check(ufbxi_obj_parse_material(uc));
  14546. } else if (cmd.length > 4 && !memcmp(cmd.data, "map_", 4)) {
  14547. ufbxi_check(ufbxi_obj_parse_mtl_map(uc, 4));
  14548. } else if (cmd.length == 4 && (!memcmp(cmd.data, "bump", 4) || !memcmp(cmd.data, "disp", 4) || !memcmp(cmd.data, "norm", 4))) {
  14549. ufbxi_check(ufbxi_obj_parse_mtl_map(uc, 0));
  14550. } else if (cmd.length == 1 && cmd.data[0] == '#') {
  14551. // Implement .mtl magic comment handling here if necessary
  14552. } else {
  14553. ufbxi_check(ufbxi_obj_parse_prop(uc, uc->obj.tokens[0], 1, true, NULL));
  14554. }
  14555. }
  14556. ufbxi_check(ufbxi_obj_flush_material(uc));
  14557. return 1;
  14558. }
  14559. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_load_mtl(ufbxi_context *uc)
  14560. {
  14561. // HACK: Reset everything and switch to loading the .mtl file globally
  14562. if (uc->close_fn) {
  14563. uc->close_fn(uc->read_user);
  14564. }
  14565. uc->read_fn = NULL;
  14566. uc->close_fn = NULL;
  14567. uc->read_user = NULL;
  14568. uc->data_begin = NULL;
  14569. uc->data = NULL;
  14570. uc->data_size = 0;
  14571. uc->yield_size = 0;
  14572. uc->eof = false;
  14573. uc->obj.eof = false;
  14574. if (uc->opts.obj_mtl_data.size > 0) {
  14575. uc->data_begin = uc->data = (const char*)uc->opts.obj_mtl_data.data;
  14576. uc->data_size = uc->opts.obj_mtl_data.size;
  14577. ufbxi_check(ufbxi_obj_parse_mtl(uc));
  14578. return 1;
  14579. }
  14580. ufbx_stream stream = { 0 };
  14581. bool has_stream = false;
  14582. bool needs_stream = false;
  14583. ufbx_blob stream_path = { 0 };
  14584. if (uc->opts.open_file_cb.fn) {
  14585. if (uc->opts.obj_mtl_path.length > 0) {
  14586. has_stream = ufbxi_open_file(&uc->opts.open_file_cb, &stream, uc->opts.obj_mtl_path.data, uc->opts.obj_mtl_path.length, NULL, &uc->ator_tmp, UFBX_OPEN_FILE_OBJ_MTL);
  14587. stream_path.data = uc->opts.obj_mtl_path.data;
  14588. stream_path.size = uc->opts.obj_mtl_path.length;
  14589. needs_stream = true;
  14590. if (!has_stream) {
  14591. ufbxi_check(ufbxi_warnf(UFBX_WARNING_MISSING_EXTERNAL_FILE, "Could not open .mtl file: %s", uc->opts.obj_mtl_path.data));
  14592. }
  14593. }
  14594. if (!has_stream && uc->opts.load_external_files && uc->obj.mtllib_relative_path.size > 0) {
  14595. ufbx_blob dst; // ufbxi_uninit
  14596. ufbxi_check(ufbxi_resolve_relative_filename(uc, (ufbxi_strblob*)&dst, (const ufbxi_strblob*)&uc->obj.mtllib_relative_path, true));
  14597. has_stream = ufbxi_open_file(&uc->opts.open_file_cb, &stream, (const char*)dst.data, dst.size, &uc->obj.mtllib_relative_path, &uc->ator_tmp, UFBX_OPEN_FILE_OBJ_MTL);
  14598. stream_path = uc->obj.mtllib_relative_path;
  14599. needs_stream = true;
  14600. if (!has_stream) {
  14601. ufbxi_check(ufbxi_warnf(UFBX_WARNING_MISSING_EXTERNAL_FILE, "Could not open .mtl file: %s", dst.data));
  14602. }
  14603. }
  14604. ufbx_string path = uc->scene.metadata.filename;
  14605. if (!has_stream && uc->opts.load_external_files && uc->opts.obj_search_mtl_by_filename && path.length > 4) {
  14606. ufbx_string ext = { path.data + path.length - 4, 4 };
  14607. if (ufbxi_match(&ext, "\\c.obj")) {
  14608. char *copy = ufbxi_push_copy(&uc->tmp, char, path.length + 1, path.data);
  14609. ufbxi_check(copy);
  14610. copy[path.length - 3] = copy[path.length - 3] == 'O' ? 'M' : 'm';
  14611. copy[path.length - 2] = copy[path.length - 2] == 'B' ? 'T' : 't';
  14612. copy[path.length - 1] = copy[path.length - 1] == 'J' ? 'L' : 'l';
  14613. has_stream = ufbxi_open_file(&uc->opts.open_file_cb, &stream, copy, path.length, NULL, &uc->ator_tmp, UFBX_OPEN_FILE_OBJ_MTL);
  14614. if (has_stream) {
  14615. ufbxi_check(ufbxi_warnf(UFBX_WARNING_IMPLICIT_MTL, "Opened .mtl file derived from .obj filename: %s", copy));
  14616. }
  14617. }
  14618. }
  14619. }
  14620. if (has_stream) {
  14621. // Adopt `stream` to ufbx read callbacks
  14622. uc->read_fn = stream.read_fn;
  14623. uc->close_fn = stream.close_fn;
  14624. uc->read_user = stream.user;
  14625. int ok = ufbxi_obj_parse_mtl(uc);
  14626. if (uc->close_fn) {
  14627. uc->close_fn(uc->read_user);
  14628. }
  14629. uc->read_fn = NULL;
  14630. uc->close_fn = NULL;
  14631. uc->read_user = NULL;
  14632. ufbxi_check(ok);
  14633. } else if (needs_stream && !uc->opts.ignore_missing_external_files) {
  14634. ufbxi_set_err_info(&uc->error, (const char*)stream_path.data, stream_path.size);
  14635. ufbxi_fail_msg("ufbxi_obj_load_mtl()", "External file not found");
  14636. }
  14637. return 1;
  14638. }
  14639. ufbxi_nodiscard static ufbxi_noinline int ufbxi_obj_load(ufbxi_context *uc)
  14640. {
  14641. ufbxi_check(ufbxi_obj_init(uc));
  14642. ufbxi_check(ufbxi_obj_parse_file(uc));
  14643. ufbxi_check(ufbxi_init_file_paths(uc));
  14644. ufbxi_check(ufbxi_obj_load_mtl(uc));
  14645. return 1;
  14646. }
  14647. ufbxi_nodiscard static ufbxi_noinline int ufbxi_mtl_load(ufbxi_context *uc)
  14648. {
  14649. ufbxi_check(ufbxi_obj_init(uc));
  14650. ufbxi_check(ufbxi_init_file_paths(uc));
  14651. ufbxi_check(ufbxi_obj_parse_mtl(uc));
  14652. return 1;
  14653. }
  14654. #else
  14655. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_obj_load(ufbxi_context *uc)
  14656. {
  14657. ufbxi_fmt_err_info(&uc->error, "UFBX_ENABLE_FORMAT_OBJ");
  14658. ufbxi_fail_msg("UFBXI_FEATURE_FORMAT_OBJ", "Feature disabled");
  14659. }
  14660. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_mtl_load(ufbxi_context *uc)
  14661. {
  14662. ufbxi_fmt_err_info(&uc->error, "UFBX_ENABLE_FORMAT_OBJ");
  14663. ufbxi_fail_msg("UFBXI_FEATURE_FORMAT_OBJ", "Feature disabled");
  14664. }
  14665. static ufbxi_forceinline void ufbxi_obj_free(ufbxi_context *uc)
  14666. {
  14667. }
  14668. #endif
  14669. // -- Scene pre-processing
  14670. typedef struct {
  14671. ufbx_element *src, *dst;
  14672. } ufbxi_pre_connection;
  14673. typedef struct {
  14674. bool has_constant_scale;
  14675. bool has_recursive_scale_helper;
  14676. bool has_skin_deformer;
  14677. ufbx_vec3 constant_scale;
  14678. uint32_t element_id;
  14679. uint32_t first_child;
  14680. uint32_t next_child;
  14681. uint32_t parent;
  14682. } ufbxi_pre_node;
  14683. typedef struct {
  14684. bool has_skin_deformer;
  14685. } ufbxi_pre_mesh;
  14686. typedef struct {
  14687. bool has_constant_value;
  14688. ufbx_vec3 constant_value;
  14689. } ufbxi_pre_anim_value;
  14690. // Called between parsing and `ufbxi_finalize_scene()`.
  14691. // This is a very messy function reminiscent of the _old_ ufbx, where we do
  14692. // multiple passes over connections without having a proper scene graph.
  14693. // This, however gives us the advantage of allowing us to modify elements
  14694. // and connections. We can, for example, add new helper nodes and redirect
  14695. // animated properties from source nodes to the helpers. The rest of ufbx
  14696. // will treat these as if they were a part of the source file.
  14697. ufbxi_nodiscard ufbxi_noinline static int ufbxi_pre_finalize_scene(ufbxi_context *uc)
  14698. {
  14699. bool required = false;
  14700. if (uc->opts.geometry_transform_handling == UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES || uc->opts.geometry_transform_handling == UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY) required = true;
  14701. if (uc->opts.inherit_mode_handling == UFBX_INHERIT_MODE_HANDLING_HELPER_NODES || uc->opts.inherit_mode_handling == UFBX_INHERIT_MODE_HANDLING_COMPENSATE || uc->opts.inherit_mode_handling == UFBX_INHERIT_MODE_HANDLING_COMPENSATE_NO_FALLBACK) required = true;
  14702. if (uc->opts.pivot_handling == UFBX_PIVOT_HANDLING_ADJUST_TO_PIVOT) required = true;
  14703. #if defined(UFBX_REGRESSION)
  14704. required = true;
  14705. #endif
  14706. if (!required) return 1;
  14707. uint32_t num_elements = uc->num_elements;
  14708. size_t num_nodes = uc->tmp_node_ids.num_items;
  14709. ufbx_element **elements = ufbxi_push_pop(&uc->tmp_parse, &uc->tmp_element_ptrs, ufbx_element*, num_elements);
  14710. ufbxi_check(elements);
  14711. size_t num_connections = uc->tmp_connections.num_items;
  14712. ufbxi_tmp_connection *tmp_connections = ufbxi_push_peek(&uc->tmp_parse, &uc->tmp_connections, ufbxi_tmp_connection, num_connections);
  14713. ufbxi_check(tmp_connections);
  14714. ufbxi_pre_connection *pre_connections = ufbxi_push(&uc->tmp_parse, ufbxi_pre_connection, num_connections);
  14715. ufbxi_check(pre_connections);
  14716. uint32_t *instance_counts = ufbxi_push_zero(&uc->tmp_parse, uint32_t, num_elements);
  14717. ufbxi_check(instance_counts);
  14718. bool *modify_not_supported = ufbxi_push_zero(&uc->tmp_parse, bool, num_elements);
  14719. ufbxi_check(modify_not_supported);
  14720. bool *has_unscaled_children = ufbxi_push_zero(&uc->tmp_parse, bool, num_nodes);
  14721. ufbxi_check(has_unscaled_children);
  14722. bool *has_scale_animation = ufbxi_push_zero(&uc->tmp_parse, bool, num_nodes);
  14723. ufbxi_check(has_scale_animation);
  14724. ufbxi_pre_node *pre_nodes = ufbxi_push_zero(&uc->tmp_parse, ufbxi_pre_node, num_nodes);
  14725. ufbxi_check(pre_nodes);
  14726. size_t num_meshes = uc->tmp_typed_element_offsets[UFBX_ELEMENT_MESH].num_items;
  14727. ufbxi_pre_mesh *pre_meshes = ufbxi_push_zero(&uc->tmp_parse, ufbxi_pre_mesh, num_meshes);
  14728. ufbxi_check(pre_meshes);
  14729. size_t num_anim_values = uc->tmp_typed_element_offsets[UFBX_ELEMENT_ANIM_VALUE].num_items;
  14730. ufbxi_pre_anim_value *pre_anim_values = ufbxi_push_zero(&uc->tmp_parse, ufbxi_pre_anim_value, num_anim_values);
  14731. ufbxi_check(pre_anim_values);
  14732. uint64_t *fbx_ids = ufbxi_push_pop(&uc->tmp_parse, &uc->tmp_element_fbx_ids, uint64_t, num_elements);
  14733. ufbxi_check(fbx_ids);
  14734. // TODO
  14735. const ufbx_real scale_epsilon = 0.001f;
  14736. const ufbx_real pivot_epsilon = 0.001f;
  14737. const ufbx_real compensate_epsilon = 0.01f;
  14738. for (size_t i = 0; i < num_elements; i++) {
  14739. ufbx_element *element = elements[i];
  14740. uint32_t id = element->typed_id;
  14741. if (element->type == UFBX_ELEMENT_NODE) {
  14742. ufbxi_pre_node *pre_node = &pre_nodes[id];
  14743. pre_node->has_constant_scale = true;
  14744. pre_node->constant_scale = ufbxi_find_vec3(&element->props, ufbxi_Lcl_Scaling, 1.0f, 1.0f, 1.0f);
  14745. pre_node->element_id = element->element_id;
  14746. pre_node->first_child = ~0u;
  14747. pre_node->next_child = ~0u;
  14748. pre_node->parent = ~0u;
  14749. } if (element->type == UFBX_ELEMENT_ANIM_VALUE) {
  14750. ufbxi_pre_anim_value *pre_value = &pre_anim_values[id];
  14751. pre_value->has_constant_value = true;
  14752. pre_value->constant_value.x = ufbxi_find_real(&element->props, ufbxi_X, UFBX_NAN);
  14753. pre_value->constant_value.x = ufbxi_find_real(&element->props, ufbxi_d_X, pre_value->constant_value.x);
  14754. pre_value->constant_value.y = ufbxi_find_real(&element->props, ufbxi_Y, UFBX_NAN);
  14755. pre_value->constant_value.y = ufbxi_find_real(&element->props, ufbxi_d_Y, pre_value->constant_value.y);
  14756. pre_value->constant_value.z = ufbxi_find_real(&element->props, ufbxi_Z, UFBX_NAN);
  14757. pre_value->constant_value.z = ufbxi_find_real(&element->props, ufbxi_d_Z, pre_value->constant_value.z);
  14758. }
  14759. }
  14760. for (size_t i = 0; i < num_connections; i++) {
  14761. ufbxi_tmp_connection *tmp = &tmp_connections[i];
  14762. ufbxi_pre_connection *pre = &pre_connections[i];
  14763. ufbxi_fbx_id_entry *src_entry = ufbxi_find_fbx_id(uc, tmp->src);
  14764. ufbxi_fbx_id_entry *dst_entry = ufbxi_find_fbx_id(uc, tmp->dst);
  14765. ufbx_element *src = src_entry ? elements[src_entry->element_id] : NULL;
  14766. ufbx_element *dst = dst_entry ? elements[dst_entry->element_id] : NULL;
  14767. pre->src = src;
  14768. pre->dst = dst;
  14769. if (!src || !dst) continue;
  14770. if (tmp->src_prop.length == 0 && tmp->dst_prop.length == 0) {
  14771. // Count number of instances of each attribute
  14772. if (dst->type == UFBX_ELEMENT_NODE) {
  14773. ufbx_node *dst_node = (ufbx_node*)dst;
  14774. if (src->type >= UFBX_ELEMENT_TYPE_FIRST_ATTRIB && src->type <= UFBX_ELEMENT_TYPE_LAST_ATTRIB) {
  14775. ++instance_counts[src->element_id];
  14776. // These must match what can be trasnsformed in `ufbxi_modify_geometry()`
  14777. switch (src->type) {
  14778. case UFBX_ELEMENT_MESH:
  14779. case UFBX_ELEMENT_LINE_CURVE:
  14780. case UFBX_ELEMENT_NURBS_CURVE:
  14781. case UFBX_ELEMENT_NURBS_SURFACE:
  14782. break; // Nop, supported
  14783. default:
  14784. modify_not_supported[dst->element_id] = true;
  14785. break;
  14786. }
  14787. }
  14788. if (src->type == UFBX_ELEMENT_NODE) {
  14789. ufbx_node *src_node = (ufbx_node*)src;
  14790. ufbxi_pre_node *pre_dst = &pre_nodes[dst_node->typed_id];
  14791. ufbxi_pre_node *pre_src = &pre_nodes[src_node->typed_id];
  14792. // Remember parent and add children into a linked list
  14793. if (pre_src->parent == ~0u) {
  14794. pre_src->parent = dst_node->typed_id;
  14795. pre_src->next_child = pre_dst->first_child;
  14796. pre_dst->first_child = src_node->typed_id;
  14797. }
  14798. if (uc->opts.inherit_mode_handling != UFBX_INHERIT_MODE_HANDLING_PRESERVE) {
  14799. if (!dst_node->is_root && src_node->original_inherit_mode != UFBX_INHERIT_MODE_NORMAL) {
  14800. has_unscaled_children[dst->typed_id] = true;
  14801. }
  14802. }
  14803. }
  14804. } else if (dst->type == UFBX_ELEMENT_MESH) {
  14805. if (src->type == UFBX_ELEMENT_SKIN_DEFORMER) {
  14806. ufbxi_pre_mesh *pre_mesh = &pre_meshes[dst->typed_id];
  14807. pre_mesh->has_skin_deformer = true;
  14808. }
  14809. }
  14810. } else if (tmp->src_prop.length == 0 && tmp->dst_prop.length != 0) {
  14811. const char *dst_prop = tmp->dst_prop.data;
  14812. if (dst->type == UFBX_ELEMENT_ANIM_VALUE && src->type == UFBX_ELEMENT_ANIM_CURVE) {
  14813. ufbx_anim_curve *src_curve = (ufbx_anim_curve*)src;
  14814. uint32_t index = 0;
  14815. if (dst_prop == ufbxi_Y || dst_prop == ufbxi_d_Y) {
  14816. index = 1;
  14817. } else if (dst_prop == ufbxi_Z || dst_prop == ufbxi_d_Z) {
  14818. index = 2;
  14819. }
  14820. ufbxi_pre_anim_value *pre_value = &pre_anim_values[dst->typed_id];
  14821. if (src_curve->max_value - src_curve->min_value >= scale_epsilon) {
  14822. pre_value->has_constant_value = false;
  14823. } else {
  14824. ufbx_real constant_value = (src_curve->min_value + src_curve->max_value) * 0.5f;
  14825. if (ufbx_isnan(pre_value->constant_value.v[index])) {
  14826. pre_value->constant_value.v[index] = constant_value;
  14827. }
  14828. if ((ufbx_real)ufbx_fabs(pre_value->constant_value.v[index] - constant_value) > scale_epsilon) {
  14829. pre_value->has_constant_value = false;
  14830. }
  14831. }
  14832. }
  14833. }
  14834. }
  14835. for (size_t i = 0; i < num_connections; i++) {
  14836. ufbxi_tmp_connection *tmp = &tmp_connections[i];
  14837. ufbxi_pre_connection *pre = &pre_connections[i];
  14838. ufbx_element *src = pre->src, *dst = pre->dst;
  14839. if (!src || !dst) continue;
  14840. if (tmp->src_prop.length == 0 && tmp->dst_prop.length == 0) {
  14841. // Count maximum number of instanced attributes in a node
  14842. if (dst->type == UFBX_ELEMENT_NODE) {
  14843. if (src->type >= UFBX_ELEMENT_TYPE_FIRST_ATTRIB && src->type <= UFBX_ELEMENT_TYPE_LAST_ATTRIB) {
  14844. instance_counts[dst->element_id] = ufbxi_max32(instance_counts[dst->element_id], instance_counts[src->element_id]);
  14845. if (src->type == UFBX_ELEMENT_MESH) {
  14846. ufbxi_pre_mesh *pre_mesh = &pre_meshes[src->typed_id];
  14847. if (pre_mesh->has_skin_deformer) {
  14848. pre_nodes[dst->typed_id].has_skin_deformer = true;
  14849. }
  14850. }
  14851. } else if (src->type == UFBX_ELEMENT_SKIN_DEFORMER) {
  14852. pre_nodes[dst->typed_id].has_skin_deformer = true;
  14853. }
  14854. }
  14855. } else if (tmp->src_prop.length == 0 && tmp->dst_prop.length != 0) {
  14856. if (dst->type == UFBX_ELEMENT_NODE) {
  14857. if (src->type == UFBX_ELEMENT_ANIM_VALUE) {
  14858. if (tmp->dst_prop.data == ufbxi_Lcl_Scaling) {
  14859. ufbxi_pre_node *pre_node = &pre_nodes[dst->typed_id];
  14860. if (pre_node->has_constant_scale) {
  14861. ufbxi_pre_anim_value *pre_value = &pre_anim_values[src->typed_id];
  14862. if (!pre_value->has_constant_value) {
  14863. pre_node->has_constant_scale = false;
  14864. } else {
  14865. ufbx_real error = 0.0f;
  14866. error += (ufbx_real)ufbx_fabs(pre_value->constant_value.x - pre_node->constant_scale.x);
  14867. error += (ufbx_real)ufbx_fabs(pre_value->constant_value.y - pre_node->constant_scale.y);
  14868. error += (ufbx_real)ufbx_fabs(pre_value->constant_value.z - pre_node->constant_scale.z);
  14869. if (error >= scale_epsilon) {
  14870. pre_node->has_constant_scale = false;
  14871. }
  14872. }
  14873. }
  14874. }
  14875. }
  14876. }
  14877. }
  14878. }
  14879. if (uc->opts.pivot_handling == UFBX_PIVOT_HANDLING_ADJUST_TO_PIVOT) {
  14880. for (size_t i = 0; i < num_nodes; i++) {
  14881. ufbxi_pre_node *pre_node = &pre_nodes[i];
  14882. ufbx_node *node = (ufbx_node*)elements[pre_node->element_id];
  14883. ufbx_vec3 rotation_pivot = ufbxi_find_vec3(&node->props, ufbxi_RotationPivot, 0.0f, 0.0f, 0.0f);
  14884. ufbx_vec3 scaling_pivot = ufbxi_find_vec3(&node->props, ufbxi_ScalingPivot, 0.0f, 0.0f, 0.0f);
  14885. if (!ufbxi_is_vec3_zero(rotation_pivot)) {
  14886. ufbx_real err = 0.0f;
  14887. err += (ufbx_real)ufbx_fabs(rotation_pivot.x - scaling_pivot.x);
  14888. err += (ufbx_real)ufbx_fabs(rotation_pivot.y - scaling_pivot.y);
  14889. err += (ufbx_real)ufbx_fabs(rotation_pivot.z - scaling_pivot.z);
  14890. bool can_modify_geometry_transform = true;
  14891. if (uc->opts.geometry_transform_handling == UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY_NO_FALLBACK) {
  14892. if (instance_counts[node->element_id] > 1 || modify_not_supported[node->element_id]) {
  14893. can_modify_geometry_transform = false;
  14894. }
  14895. }
  14896. // Currently, geometry transform messes up skinning
  14897. if (pre_node->has_skin_deformer) {
  14898. can_modify_geometry_transform = false;
  14899. }
  14900. if (err <= pivot_epsilon && can_modify_geometry_transform) {
  14901. size_t num_props = node->props.props.count;
  14902. ufbx_prop *new_props = ufbxi_push_zero(&uc->result, ufbx_prop, num_props + 3);
  14903. ufbxi_check(new_props);
  14904. memcpy(new_props, node->props.props.data, num_props * sizeof(ufbx_prop));
  14905. ufbx_vec3 geometric_translation = ufbxi_find_vec3(&node->props, ufbxi_GeometricTranslation, 0.0f, 0.0f, 0.0f);
  14906. geometric_translation.x -= rotation_pivot.x;
  14907. geometric_translation.y -= rotation_pivot.y;
  14908. geometric_translation.z -= rotation_pivot.z;
  14909. ufbx_prop *dst = new_props + num_props;
  14910. ufbxi_init_synthetic_vec3_prop(&dst[0], ufbxi_RotationPivot, &ufbx_zero_vec3, UFBX_PROP_VECTOR);
  14911. ufbxi_init_synthetic_vec3_prop(&dst[1], ufbxi_ScalingPivot, &ufbx_zero_vec3, UFBX_PROP_VECTOR);
  14912. ufbxi_init_synthetic_vec3_prop(&dst[2], ufbxi_GeometricTranslation, &geometric_translation, UFBX_PROP_VECTOR);
  14913. node->props.props.data = new_props;
  14914. node->props.props.count = num_props + 3;
  14915. ufbxi_check(ufbxi_sort_properties(uc, node->props.props.data, node->props.props.count));
  14916. ufbxi_deduplicate_properties(&node->props.props);
  14917. node->adjust_pre_translation = ufbxi_add3(node->adjust_pre_translation, rotation_pivot);
  14918. node->has_adjust_transform = true;
  14919. uint32_t ix = pre_node->first_child;
  14920. while (ix != ~0u) {
  14921. ufbxi_pre_node *pre_child = &pre_nodes[ix];
  14922. ufbx_node *child = (ufbx_node*)elements[pre_child->element_id];
  14923. child->adjust_pre_translation = ufbxi_sub3(child->adjust_pre_translation, rotation_pivot);
  14924. child->has_adjust_transform = true;
  14925. ix = pre_child->next_child;
  14926. }
  14927. }
  14928. }
  14929. }
  14930. }
  14931. for (size_t i = 0; i < num_elements; i++) {
  14932. ufbx_element *element = elements[i];
  14933. uint64_t fbx_id = fbx_ids[i];
  14934. if (element->type == UFBX_ELEMENT_NODE) {
  14935. ufbx_node *node = (ufbx_node*)element;
  14936. bool requires_helper_node = false;
  14937. if (uc->opts.geometry_transform_handling == UFBX_GEOMETRY_TRANSFORM_HANDLING_HELPER_NODES) {
  14938. requires_helper_node = true;
  14939. } else if (uc->opts.geometry_transform_handling == UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY) {
  14940. // Setup a geometry transform helper for nodes that have instanced attributes
  14941. requires_helper_node = instance_counts[i] > 1 || modify_not_supported[i];
  14942. }
  14943. if (requires_helper_node) {
  14944. ufbxi_check(ufbxi_setup_geometry_transform_helper(uc, node, fbx_id));
  14945. }
  14946. }
  14947. }
  14948. for (size_t i = 0; i < num_elements; i++) {
  14949. ufbx_element *element = elements[i];
  14950. uint64_t fbx_id = fbx_ids[i];
  14951. if (element->type == UFBX_ELEMENT_NODE) {
  14952. ufbx_node *node = (ufbx_node*)element;
  14953. if (has_unscaled_children[node->typed_id] && !node->scale_helper) {
  14954. ufbxi_pre_node *pre_node = &pre_nodes[node->typed_id];
  14955. ufbx_real ref = uc->opts.inherit_mode_handling == UFBX_INHERIT_MODE_HANDLING_COMPENSATE
  14956. ? pre_node->constant_scale.x : (ufbx_real)1.0f;
  14957. ufbx_vec3 scale = pre_node->constant_scale;
  14958. ufbx_real dx = (ufbx_real)ufbx_fabs(scale.x - ref);
  14959. ufbx_real dy = (ufbx_real)ufbx_fabs(scale.y - ref);
  14960. ufbx_real dz = (ufbx_real)ufbx_fabs(scale.z - ref);
  14961. if ((dx + dy + dz >= scale_epsilon || !pre_node->has_constant_scale || (ufbx_real)ufbx_fabs(scale.x) <= compensate_epsilon)
  14962. && uc->opts.inherit_mode_handling != UFBX_INHERIT_MODE_HANDLING_COMPENSATE_NO_FALLBACK) {
  14963. ufbxi_check(ufbxi_setup_scale_helper(uc, node, fbx_id));
  14964. // If we added a geometry transform helper that may scale further helpers
  14965. // recursively for all child nodes using `UFBX_INHERIT_MODE_COMPONENTWISE_SCALE`
  14966. // This is guaranteed to terminate as `ufbxi_pre_node` may only have one parent,
  14967. // meaning any cycles must contain `node` itself.
  14968. uint32_t ix = pre_node->first_child;
  14969. while (ix != ~0u && ix != node->typed_id) {
  14970. ufbxi_pre_node *pre_child = &pre_nodes[ix];
  14971. ufbx_node *child = (ufbx_node*)elements[pre_child->element_id];
  14972. if (pre_child->parent != node->typed_id || child->original_inherit_mode == UFBX_INHERIT_MODE_COMPONENTWISE_SCALE) {
  14973. if (!pre_child->has_recursive_scale_helper && child->original_inherit_mode != UFBX_INHERIT_MODE_NORMAL) {
  14974. pre_child->has_recursive_scale_helper = true;
  14975. uint64_t child_fbx_id = fbx_ids[pre_child->element_id];
  14976. ufbxi_check(ufbxi_setup_scale_helper(uc, child, child_fbx_id));
  14977. child->is_scale_compensate_parent = false;
  14978. // Traverse to children if any
  14979. if (pre_child->first_child != ~0u) {
  14980. ix = pre_child->first_child;
  14981. continue;
  14982. }
  14983. }
  14984. }
  14985. // Move to next child, popping parents until we find one
  14986. while (pre_child->next_child == ~0u) {
  14987. ix = pre_child->parent;
  14988. if (ix == node->typed_id) break;
  14989. pre_child = &pre_nodes[ix];
  14990. }
  14991. if (ix != node->typed_id) {
  14992. ix = pre_child->next_child;
  14993. }
  14994. }
  14995. } else if (uc->opts.inherit_mode_handling == UFBX_INHERIT_MODE_HANDLING_COMPENSATE || uc->opts.inherit_mode_handling == UFBX_INHERIT_MODE_HANDLING_COMPENSATE_NO_FALLBACK) {
  14996. if ((ufbx_real)ufbx_fabs(scale.x - 1.0f) >= scale_epsilon) {
  14997. node->is_scale_compensate_parent = true;
  14998. }
  14999. }
  15000. }
  15001. }
  15002. }
  15003. return 1;
  15004. }
  15005. // -- Scene processing
  15006. static ufbxi_noinline ufbx_element *ufbxi_find_element_by_fbx_id(ufbxi_context *uc, uint64_t fbx_id)
  15007. {
  15008. ufbxi_fbx_id_entry *entry = ufbxi_find_fbx_id(uc, fbx_id);
  15009. if (entry) {
  15010. return uc->scene.elements.data[entry->element_id];
  15011. }
  15012. return NULL;
  15013. }
  15014. ufbxi_forceinline static bool ufbxi_cmp_name_element_less(const ufbx_name_element *a, const ufbx_name_element *b)
  15015. {
  15016. if (a->_internal_key != b->_internal_key) return a->_internal_key < b->_internal_key;
  15017. int cmp = strcmp(a->name.data, b->name.data);
  15018. if (cmp != 0) return cmp < 0;
  15019. return a->type < b->type;
  15020. }
  15021. ufbxi_forceinline static bool ufbxi_cmp_name_element_less_ref(const ufbx_name_element *a, ufbx_string name, ufbx_element_type type, uint32_t key)
  15022. {
  15023. if (a->_internal_key != key) return a->_internal_key < key;
  15024. int cmp = ufbxi_str_cmp(a->name, name);
  15025. if (cmp != 0) return cmp < 0;
  15026. return a->type < type;
  15027. }
  15028. ufbxi_forceinline static bool ufbxi_cmp_prop_less_ref(const ufbx_prop *a, ufbx_string name, uint32_t key)
  15029. {
  15030. if (a->_internal_key != key) return a->_internal_key < key;
  15031. return ufbxi_str_less(a->name, name);
  15032. }
  15033. ufbxi_forceinline static bool ufbxi_cmp_prop_less_concat(const ufbx_prop *a, const ufbx_string *parts, size_t num_parts, uint32_t key)
  15034. {
  15035. if (a->_internal_key != key) return a->_internal_key < key;
  15036. return ufbxi_concat_str_cmp(&a->name, parts, num_parts) < 0;
  15037. }
  15038. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_name_elements(ufbxi_context *uc, ufbx_name_element *name_elems, size_t count)
  15039. {
  15040. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_name_element)));
  15041. ufbxi_macro_stable_sort(ufbx_name_element, 32, name_elems, uc->tmp_arr, count,
  15042. ( ufbxi_cmp_name_element_less(a, b) ) );
  15043. return 1;
  15044. }
  15045. ufbxi_noinline static bool ufbxi_cmp_node_less(ufbx_node *a, ufbx_node *b)
  15046. {
  15047. if (a->node_depth != b->node_depth) return a->node_depth < b->node_depth;
  15048. if (a->parent && b->parent) {
  15049. uint32_t a_pid = a->parent->element.element_id, b_pid = b->parent->element.element_id;
  15050. if (a_pid != b_pid) return a_pid < b_pid;
  15051. } else {
  15052. ufbx_assert(a->parent == NULL && b->parent == NULL);
  15053. }
  15054. if (a->is_geometry_transform_helper != b->is_geometry_transform_helper) {
  15055. // Sort geometry transform helpers always before rest of the children.
  15056. return (unsigned)a->is_geometry_transform_helper > (unsigned)b->is_geometry_transform_helper;
  15057. }
  15058. if (a->is_scale_helper != b->is_scale_helper) {
  15059. // Sort scale helpers after geometry transform helpers.
  15060. return (unsigned)a->is_scale_helper > (unsigned)b->is_scale_helper;
  15061. }
  15062. return a->element.element_id < b->element.element_id;
  15063. }
  15064. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_node_ptrs(ufbxi_context *uc, ufbx_node **nodes, size_t count)
  15065. {
  15066. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_node*)));
  15067. ufbxi_macro_stable_sort(ufbx_node*, 32, nodes, uc->tmp_arr, count,
  15068. ( ufbxi_cmp_node_less(*a, *b) ) );
  15069. return 1;
  15070. }
  15071. ufbxi_nodiscard ufbxi_noinline static int ufbxi_cmp_tmp_material_texture_less(const ufbxi_tmp_material_texture *a, const ufbxi_tmp_material_texture *b)
  15072. {
  15073. if (a->material_id != b->material_id) return a->material_id < b->material_id;
  15074. if (a->texture_id != b->texture_id) return a->texture_id < b->texture_id;
  15075. return ufbxi_str_less(a->prop_name, b->prop_name);
  15076. }
  15077. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_tmp_material_textures(ufbxi_context *uc, ufbxi_tmp_material_texture *mat_texs, size_t count)
  15078. {
  15079. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbxi_tmp_material_texture)));
  15080. ufbxi_macro_stable_sort(ufbxi_tmp_material_texture, 32, mat_texs, uc->tmp_arr, count,
  15081. ( ufbxi_cmp_tmp_material_texture_less(a, b) ));
  15082. return 1;
  15083. }
  15084. // We need to be able to assume no padding!
  15085. ufbx_static_assert(connection_size, sizeof(ufbx_connection) == sizeof(ufbx_element*)*2 + sizeof(ufbx_string)*2);
  15086. ufbxi_forceinline static bool ufbxi_cmp_connection_less(ufbx_connection *a, ufbx_connection *b, size_t index)
  15087. {
  15088. ufbx_element *a_elem = (&a->src)[index], *b_elem = (&b->src)[index];
  15089. if (a_elem != b_elem) return a_elem < b_elem;
  15090. int cmp = strcmp((&a->src_prop)[index].data, (&b->src_prop)[index].data);
  15091. if (cmp != 0) return cmp < 0;
  15092. cmp = strcmp((&a->src_prop)[index ^ 1].data, (&b->src_prop)[index ^ 1].data);
  15093. return cmp < 0;
  15094. }
  15095. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_connections(ufbxi_context *uc, ufbx_connection *connections, size_t count, size_t index)
  15096. {
  15097. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_connection)));
  15098. ufbxi_macro_stable_sort(ufbx_connection, 32, connections, uc->tmp_arr, count, ( ufbxi_cmp_connection_less(a, b, index) ));
  15099. return 1;
  15100. }
  15101. static uint64_t ufbxi_find_attribute_fbx_id(ufbxi_context *uc, uint64_t node_fbx_id)
  15102. {
  15103. uint32_t hash = ufbxi_hash64(node_fbx_id);
  15104. ufbxi_fbx_attr_entry *entry = ufbxi_map_find(&uc->fbx_attr_map, ufbxi_fbx_attr_entry, hash, &node_fbx_id);
  15105. if (entry) {
  15106. return entry->attr_fbx_id;
  15107. }
  15108. return node_fbx_id;
  15109. }
  15110. ufbxi_nodiscard ufbxi_noinline static int ufbxi_resolve_connections(ufbxi_context *uc)
  15111. {
  15112. size_t num_connections = uc->tmp_connections.num_items;
  15113. ufbxi_tmp_connection *tmp_connections = ufbxi_push_pop(&uc->tmp, &uc->tmp_connections, ufbxi_tmp_connection, num_connections);
  15114. ufbxi_buf_free(&uc->tmp_connections);
  15115. ufbxi_check(tmp_connections);
  15116. // NOTE: We truncate this array in case not all connections are resolved
  15117. uc->scene.connections_src.data = ufbxi_push(&uc->result, ufbx_connection, num_connections);
  15118. ufbxi_check(uc->scene.connections_src.data);
  15119. // HACK: Translate property connections from node to attribute if
  15120. // the property name is not included in the known node properties.
  15121. if (uc->version > 0 && uc->version < 7000) {
  15122. ufbxi_for(ufbxi_tmp_connection, tmp_conn, tmp_connections, num_connections) {
  15123. if (tmp_conn->src_prop.length > 0 && !ufbxi_is_node_property(uc, tmp_conn->src_prop.data)) {
  15124. tmp_conn->src = ufbxi_find_attribute_fbx_id(uc, tmp_conn->src);
  15125. }
  15126. if (tmp_conn->dst_prop.length > 0 && !ufbxi_is_node_property(uc, tmp_conn->dst_prop.data)) {
  15127. tmp_conn->dst = ufbxi_find_attribute_fbx_id(uc, tmp_conn->dst);
  15128. }
  15129. }
  15130. }
  15131. ufbxi_for(ufbxi_tmp_connection, tmp_conn, tmp_connections, num_connections) {
  15132. ufbx_element *src = ufbxi_find_element_by_fbx_id(uc, tmp_conn->src);
  15133. ufbx_element *dst = ufbxi_find_element_by_fbx_id(uc, tmp_conn->dst);
  15134. if (!src || !dst) continue;
  15135. if (!uc->opts.disable_quirks) {
  15136. // Some exporters connect arbitrary non-nodes to root breaking further code, ignore those connections here!
  15137. if (dst->type == UFBX_ELEMENT_NODE && src->type != UFBX_ELEMENT_NODE && ((ufbx_node*)dst)->is_root) {
  15138. ufbxi_check(ufbxi_warnf_tag(UFBX_WARNING_BAD_ELEMENT_CONNECTED_TO_ROOT, src->element_id, "Non-node element connected to root"));
  15139. continue;
  15140. }
  15141. }
  15142. // Remap connections to geometry transform helpers if necessary, see `ufbxi_setup_geometry_transform_helper()` for how these are setup.
  15143. if (uc->has_geometry_transform_nodes) {
  15144. if (dst->type == UFBX_ELEMENT_NODE && src->type >= UFBX_ELEMENT_TYPE_FIRST_ATTRIB && src->type <= UFBX_ELEMENT_TYPE_LAST_ATTRIB) {
  15145. ufbx_node *node = (ufbx_node*)dst;
  15146. if (node->has_geometry_transform) {
  15147. ufbxi_node_extra *extra = (ufbxi_node_extra*)ufbxi_get_element_extra(uc, node->element_id);
  15148. ufbx_assert(extra);
  15149. dst = uc->scene.elements.data[extra->geometry_helper_id];
  15150. ufbx_assert(dst->type == UFBX_ELEMENT_NODE && ((ufbx_node*)dst)->is_geometry_transform_helper);
  15151. }
  15152. }
  15153. }
  15154. // Remap connections to scale helpers if necessary, see `ufbxi_setup_scale_helper()` for how these are setup.
  15155. if (uc->has_scale_helper_nodes) {
  15156. if (dst->type == UFBX_ELEMENT_NODE) {
  15157. ufbx_node *dst_node = (ufbx_node*)dst;
  15158. if (dst_node->scale_helper) {
  15159. if (src->type == UFBX_ELEMENT_NODE) {
  15160. ufbx_node *src_node = (ufbx_node*)src;
  15161. if (!src_node->is_scale_helper && src_node->original_inherit_mode == UFBX_INHERIT_MODE_NORMAL) {
  15162. dst = &dst_node->scale_helper->element;
  15163. }
  15164. } else if (src->type == UFBX_ELEMENT_ANIM_VALUE) {
  15165. if (tmp_conn->dst_prop.data == ufbxi_Lcl_Scaling) {
  15166. dst = &dst_node->scale_helper->element;
  15167. }
  15168. } else {
  15169. dst = &dst_node->scale_helper->element;
  15170. }
  15171. }
  15172. } else if (src->type == UFBX_ELEMENT_NODE) {
  15173. ufbx_node *src_node = (ufbx_node*)src;
  15174. if (src_node->scale_helper) {
  15175. if (dst->type == UFBX_ELEMENT_SKIN_CLUSTER) {
  15176. src = &src_node->scale_helper->element;
  15177. }
  15178. }
  15179. }
  15180. }
  15181. // Translate deformers to point to the geometry in 6100, we don't need to worry about
  15182. // blend shapes here as they're always connected synthetically in older files.
  15183. if (uc->version > 0 && uc->version < 7000 && dst->type == UFBX_ELEMENT_NODE) {
  15184. if (src->type == UFBX_ELEMENT_SKIN_DEFORMER || src->type == UFBX_ELEMENT_CACHE_DEFORMER) {
  15185. uint64_t dst_id = ufbxi_find_attribute_fbx_id(uc, tmp_conn->dst);
  15186. ufbx_element *dst_elem = ufbxi_find_element_by_fbx_id(uc, dst_id);
  15187. if (dst_elem) {
  15188. dst = dst_elem;
  15189. }
  15190. }
  15191. }
  15192. ufbx_connection *conn = &uc->scene.connections_src.data[uc->scene.connections_src.count++];
  15193. conn->src = src;
  15194. conn->dst = dst;
  15195. conn->src_prop = tmp_conn->src_prop;
  15196. conn->dst_prop = tmp_conn->dst_prop;
  15197. }
  15198. uc->scene.connections_dst.count = uc->scene.connections_src.count;
  15199. uc->scene.connections_dst.data = ufbxi_push_copy(&uc->result, ufbx_connection,
  15200. uc->scene.connections_src.count, uc->scene.connections_src.data);
  15201. ufbxi_check(uc->scene.connections_dst.data);
  15202. ufbxi_check(ufbxi_sort_connections(uc, uc->scene.connections_src.data, uc->scene.connections_src.count, 0));
  15203. ufbxi_check(ufbxi_sort_connections(uc, uc->scene.connections_dst.data, uc->scene.connections_dst.count, 1));
  15204. // We don't need the temporary connections at this point anymore
  15205. ufbxi_buf_free(&uc->tmp_connections);
  15206. return 1;
  15207. }
  15208. ufbxi_nodiscard ufbxi_noinline static int ufbxi_add_connections_to_elements(ufbxi_context *uc)
  15209. {
  15210. ufbx_connection *conn_src = uc->scene.connections_src.data;
  15211. ufbx_connection *conn_src_end = ufbxi_add_ptr(conn_src, uc->scene.connections_src.count);
  15212. ufbx_connection *conn_dst = uc->scene.connections_dst.data;
  15213. ufbx_connection *conn_dst_end = ufbxi_add_ptr(conn_dst, uc->scene.connections_dst.count);
  15214. ufbxi_for_ptr(ufbx_element, p_elem, uc->scene.elements.data, uc->scene.elements.count) {
  15215. ufbx_element *elem = *p_elem;
  15216. uint32_t id = elem->element_id;
  15217. while (conn_src < conn_src_end && conn_src->src->element_id < id) conn_src++;
  15218. while (conn_dst < conn_dst_end && conn_dst->dst->element_id < id) conn_dst++;
  15219. ufbx_connection *src_end = conn_src, *dst_end = conn_dst;
  15220. while (src_end < conn_src_end && src_end->src->element_id == id) src_end++;
  15221. while (dst_end < conn_dst_end && dst_end->dst->element_id == id) dst_end++;
  15222. elem->connections_src.data = conn_src;
  15223. elem->connections_src.count = ufbxi_to_size(src_end - conn_src);
  15224. elem->connections_dst.data = conn_dst;
  15225. elem->connections_dst.count = ufbxi_to_size(dst_end - conn_dst);
  15226. // Setup animated properties
  15227. // TODO: It seems we're invalidating a lot of properties here actually, maybe they
  15228. // should be initially pushed to `tmp` instead of result if this happens so much..
  15229. {
  15230. ufbx_prop *prop = elem->props.props.data, *prop_end = ufbxi_add_ptr(prop, elem->props.props.count);
  15231. ufbx_prop *copy_start = prop;
  15232. bool needs_copy = false;
  15233. size_t num_animated = 0, num_synthetic = 0;
  15234. for (;;) {
  15235. // Scan to the next animation connection
  15236. for (; conn_dst < dst_end; conn_dst++) {
  15237. if (conn_dst->dst_prop.length == 0) continue;
  15238. if (conn_dst->src_prop.length > 0) break;
  15239. if (conn_dst->src->type == UFBX_ELEMENT_ANIM_VALUE) break;
  15240. }
  15241. ufbx_string name = ufbx_empty_string;
  15242. if (conn_dst < dst_end) {
  15243. name = conn_dst->dst_prop;
  15244. }
  15245. if (name.length == 0) break;
  15246. // NOTE: "Animated" properties also include connected ones as we need
  15247. // to resolve them during evaluation
  15248. num_animated++;
  15249. ufbx_anim_value *anim_value = NULL;
  15250. uint32_t flags = 0;
  15251. for (; conn_dst < dst_end && conn_dst->dst_prop.data == name.data; conn_dst++) {
  15252. if (conn_dst->src_prop.length > 0) {
  15253. flags |= UFBX_PROP_FLAG_CONNECTED;
  15254. } else if (conn_dst->src->type == UFBX_ELEMENT_ANIM_VALUE) {
  15255. anim_value = (ufbx_anim_value*)conn_dst->src;
  15256. flags |= UFBX_PROP_FLAG_ANIMATED;
  15257. }
  15258. }
  15259. uint32_t key = ufbxi_get_name_key(name.data, name.length);
  15260. while (prop != prop_end && ufbxi_name_key_less(prop, name.data, name.length, key)) prop++;
  15261. if (prop != prop_end && prop->name.data == name.data) {
  15262. prop->flags = (ufbx_prop_flags)((uint32_t)prop->flags | flags);
  15263. } else {
  15264. // Animated property that is not in the element property list
  15265. // Copy the preceding properties to the stack, then push a
  15266. // synthetic property for the animated property.
  15267. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_prop, ufbxi_to_size(prop - copy_start), copy_start));
  15268. copy_start = prop;
  15269. needs_copy = true;
  15270. // Let's hope we can find the property in the defaults at least
  15271. ufbx_prop anim_def_prop;
  15272. ufbx_prop *def_prop = NULL;
  15273. if (elem->props.defaults) {
  15274. def_prop = ufbxi_find_prop_with_key(elem->props.defaults, name.data, key);
  15275. } else if (anim_value) {
  15276. memset(&anim_def_prop, 0, sizeof(anim_def_prop));
  15277. // Hack a couple of common types
  15278. ufbx_prop_type type = UFBX_PROP_UNKNOWN;
  15279. if (name.data == ufbxi_Lcl_Translation) type = UFBX_PROP_TRANSLATION;
  15280. else if (name.data == ufbxi_Lcl_Rotation) type = UFBX_PROP_ROTATION;
  15281. else if (name.data == ufbxi_Lcl_Scaling) {
  15282. type = UFBX_PROP_SCALING;
  15283. anim_def_prop.value_vec3.x = 1.0f;
  15284. anim_def_prop.value_vec3.y = 1.0f;
  15285. anim_def_prop.value_vec3.z = 1.0f;
  15286. }
  15287. // Property values are only defined in anim_props on legacy files
  15288. if (uc->version < 6000) {
  15289. anim_def_prop.value_vec3 = anim_value->default_value;
  15290. }
  15291. anim_def_prop.type = type;
  15292. def_prop = &anim_def_prop;
  15293. } else {
  15294. flags |= UFBX_PROP_FLAG_NO_VALUE;
  15295. }
  15296. ufbx_prop *new_prop = ufbxi_push_zero(&uc->tmp_stack, ufbx_prop, 1);
  15297. ufbxi_check(new_prop);
  15298. if (def_prop) *new_prop = *def_prop;
  15299. flags |= (uint32_t)new_prop->flags;
  15300. new_prop->flags = (ufbx_prop_flags)(UFBX_PROP_FLAG_ANIMATABLE | UFBX_PROP_FLAG_SYNTHETIC | flags);
  15301. new_prop->name = name;
  15302. new_prop->_internal_key = key;
  15303. new_prop->value_str = ufbx_empty_string;
  15304. new_prop->value_blob = ufbx_empty_blob;
  15305. num_synthetic++;
  15306. }
  15307. }
  15308. // Copy the properties if necessary
  15309. if (needs_copy) {
  15310. size_t num_new_props = elem->props.props.count + num_synthetic;
  15311. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_prop, ufbxi_to_size(prop_end - copy_start), copy_start));
  15312. elem->props.props.data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_prop, num_new_props);
  15313. ufbxi_check(elem->props.props.data);
  15314. elem->props.props.count = num_new_props;
  15315. }
  15316. elem->props.num_animated = num_animated;
  15317. }
  15318. conn_src = src_end;
  15319. conn_dst = dst_end;
  15320. }
  15321. return 1;
  15322. }
  15323. ufbxi_nodiscard ufbxi_noinline static int ufbxi_linearize_nodes(ufbxi_context *uc)
  15324. {
  15325. size_t num_nodes = uc->tmp_node_ids.num_items;
  15326. uint32_t *node_ids = ufbxi_push_pop(&uc->tmp, &uc->tmp_node_ids, uint32_t, num_nodes);
  15327. ufbxi_buf_free(&uc->tmp_node_ids);
  15328. ufbxi_check(node_ids);
  15329. ufbx_node **node_ptrs = ufbxi_push(&uc->tmp_stack, ufbx_node*, num_nodes);
  15330. ufbxi_check(node_ptrs);
  15331. // Fetch the node pointers
  15332. for (size_t i = 0; i < num_nodes; i++) {
  15333. node_ptrs[i] = (ufbx_node*)uc->scene.elements.data[node_ids[i]];
  15334. ufbx_assert(node_ptrs[i]->element.type == UFBX_ELEMENT_NODE);
  15335. }
  15336. uc->scene.root_node = node_ptrs[0];
  15337. size_t *node_offsets = ufbxi_push_pop(&uc->tmp_stack, &uc->tmp_typed_element_offsets[UFBX_ELEMENT_NODE], size_t, num_nodes);
  15338. ufbxi_check(node_offsets);
  15339. // Hook up the parent nodes, we'll assume that there's no cycles at this point
  15340. ufbxi_for_ptr(ufbx_node, p_node, node_ptrs, num_nodes) {
  15341. ufbx_node *node = *p_node;
  15342. // Pre-6000 files don't have any explicit root connections so they must always
  15343. // be connected to the root..
  15344. if (node->parent == NULL && !(uc->opts.allow_nodes_out_of_root && uc->version >= 6000)) {
  15345. if (node != uc->scene.root_node) {
  15346. node->parent = uc->scene.root_node;
  15347. }
  15348. }
  15349. ufbxi_for_list(ufbx_connection, conn, node->element.connections_dst) {
  15350. if (conn->src_prop.length > 0 || conn->dst_prop.length > 0) continue;
  15351. if (conn->src->type != UFBX_ELEMENT_NODE) continue;
  15352. ((ufbx_node*)conn->src)->parent = node;
  15353. }
  15354. }
  15355. // Count the parent depths and child amounts
  15356. ufbxi_for_ptr(ufbx_node, p_node, node_ptrs, num_nodes) {
  15357. ufbx_node *node = *p_node;
  15358. uint32_t depth = 0;
  15359. for (ufbx_node *p = node->parent; p; p = p->parent) {
  15360. depth += p->node_depth + 1;
  15361. if (p->node_depth > 0) break;
  15362. ufbxi_check_msg(depth <= num_nodes, "Cyclic node hierarchy");
  15363. }
  15364. if (uc->opts.node_depth_limit > 0) {
  15365. ufbxi_check_msg(depth <= uc->opts.node_depth_limit, "Node depth limit exceeded");
  15366. }
  15367. node->node_depth = depth;
  15368. // Second pass to cache the depths to avoid O(n^2)
  15369. for (ufbx_node *p = node->parent; p; p = p->parent) {
  15370. if (--depth <= p->node_depth) break;
  15371. p->node_depth = depth;
  15372. }
  15373. }
  15374. ufbxi_check(ufbxi_sort_node_ptrs(uc, node_ptrs, num_nodes));
  15375. for (uint32_t i = 0; i < num_nodes; i++) {
  15376. size_t *p_offset = ufbxi_push(&uc->tmp_typed_element_offsets[UFBX_ELEMENT_NODE], size_t, 1);
  15377. ufbxi_check(p_offset);
  15378. ufbx_node *node = node_ptrs[i];
  15379. uint32_t original_id = node->element.typed_id;
  15380. node->element.typed_id = i;
  15381. *p_offset = node_offsets[original_id];
  15382. }
  15383. // Pop the temporary arrays
  15384. ufbxi_pop(&uc->tmp_stack, size_t, num_nodes, NULL);
  15385. ufbxi_pop(&uc->tmp_stack, ufbx_node*, num_nodes, NULL);
  15386. return 1;
  15387. }
  15388. ufbxi_nodiscard ufbxi_noinline static ufbx_connection_list ufbxi_find_dst_connections(ufbx_element *element, const char *prop)
  15389. {
  15390. if (!prop) prop = ufbxi_empty_char;
  15391. size_t begin = element->connections_dst.count, end = begin;
  15392. ufbxi_macro_lower_bound_eq(ufbx_connection, 32, &begin,
  15393. element->connections_dst.data, 0, element->connections_dst.count,
  15394. (strcmp(a->dst_prop.data, prop) < 0),
  15395. (a->dst_prop.data == prop && a->src_prop.length == 0));
  15396. ufbxi_macro_upper_bound_eq(ufbx_connection, 32, &end,
  15397. element->connections_dst.data, begin, element->connections_dst.count,
  15398. (a->dst_prop.data == prop && a->src_prop.length == 0));
  15399. ufbx_connection_list result = { element->connections_dst.data + begin, end - begin };
  15400. return result;
  15401. }
  15402. ufbxi_nodiscard ufbxi_noinline static ufbx_connection_list ufbxi_find_src_connections(ufbx_element *element, const char *prop)
  15403. {
  15404. if (!prop) prop = ufbxi_empty_char;
  15405. size_t begin = element->connections_src.count, end = begin;
  15406. ufbxi_macro_lower_bound_eq(ufbx_connection, 32, &begin,
  15407. element->connections_src.data, 0, element->connections_src.count,
  15408. (strcmp(a->src_prop.data, prop) < 0),
  15409. (a->src_prop.data == prop && a->dst_prop.length == 0));
  15410. ufbxi_macro_upper_bound_eq(ufbx_connection, 32, &end,
  15411. element->connections_src.data, begin, element->connections_src.count,
  15412. (a->src_prop.data == prop && a->dst_prop.length == 0));
  15413. ufbx_connection_list result = { element->connections_src.data + begin, end - begin };
  15414. return result;
  15415. }
  15416. ufbxi_nodiscard static ufbx_element *ufbxi_get_element_node(ufbx_element *element)
  15417. {
  15418. if (!element) return NULL;
  15419. if (element->type == UFBX_ELEMENT_NODE) {
  15420. ufbx_node *node = (ufbx_node*)element;
  15421. if (node->is_geometry_transform_helper) return (ufbx_element*)node->parent;
  15422. return NULL;
  15423. } else {
  15424. return element->instances.count > 0 ? &element->instances.data[0]->element : NULL;
  15425. }
  15426. }
  15427. ufbxi_nodiscard ufbxi_noinline static int ufbxi_fetch_dst_elements(ufbxi_context *uc, void *p_dst_list, ufbx_element *element, bool search_node, bool ignore_duplicates, const char *prop, ufbx_element_type src_type)
  15428. {
  15429. size_t num_elements = 0;
  15430. do {
  15431. ufbx_connection_list conns = ufbxi_find_dst_connections(element, prop);
  15432. ufbxi_for_list(ufbx_connection, conn, conns) {
  15433. if (conn->src->type == src_type) {
  15434. if (ignore_duplicates) {
  15435. uint32_t element_id = conn->src->element_id;
  15436. if (uc->tmp_element_flag[element_id]) {
  15437. ufbxi_check(ufbxi_warnf_tag(UFBX_WARNING_DUPLICATE_CONNECTION, element_id, "Duplicate connection to %u", element->element_id));
  15438. continue;
  15439. }
  15440. uc->tmp_element_flag[element_id] = 1;
  15441. }
  15442. ufbx_element **p_elem = ufbxi_push(&uc->tmp_stack, ufbx_element*, 1);
  15443. ufbxi_check(p_elem);
  15444. *p_elem = conn->src;
  15445. num_elements++;
  15446. }
  15447. }
  15448. } while (search_node && (element = ufbxi_get_element_node(element)) != NULL);
  15449. ufbx_element_list *list = (ufbx_element_list*)p_dst_list;
  15450. list->data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_element*, num_elements);
  15451. list->count = num_elements;
  15452. ufbxi_check(list->data);
  15453. if (ignore_duplicates) {
  15454. ufbxi_for_ptr_list(ufbx_element, p_elem, *list) {
  15455. uc->tmp_element_flag[(*p_elem)->element_id] = 0;
  15456. }
  15457. }
  15458. return 1;
  15459. }
  15460. ufbxi_nodiscard ufbxi_noinline static int ufbxi_fetch_src_elements(ufbxi_context *uc, void *p_dst_list, ufbx_element *element, bool search_node, bool ignore_duplicates, const char *prop, ufbx_element_type dst_type)
  15461. {
  15462. size_t num_elements = 0;
  15463. do {
  15464. ufbx_connection_list conns = ufbxi_find_src_connections(element, prop);
  15465. ufbxi_for_list(ufbx_connection, conn, conns) {
  15466. if (conn->dst->type == dst_type) {
  15467. if (ignore_duplicates) {
  15468. uint32_t element_id = conn->dst->element_id;
  15469. if (uc->tmp_element_flag[element_id]) {
  15470. ufbxi_check(ufbxi_warnf_tag(UFBX_WARNING_DUPLICATE_CONNECTION, element_id, "Duplicate connection to %u", element->element_id));
  15471. continue;
  15472. }
  15473. uc->tmp_element_flag[element_id] = 1;
  15474. }
  15475. ufbx_element **p_elem = ufbxi_push(&uc->tmp_stack, ufbx_element*, 1);
  15476. ufbxi_check(p_elem);
  15477. *p_elem = conn->dst;
  15478. num_elements++;
  15479. }
  15480. }
  15481. } while (search_node && (element = ufbxi_get_element_node(element)) != NULL);
  15482. ufbx_element_list *list = (ufbx_element_list*)p_dst_list;
  15483. list->data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_element*, num_elements);
  15484. list->count = num_elements;
  15485. ufbxi_check(list->data);
  15486. if (ignore_duplicates) {
  15487. ufbxi_for_ptr_list(ufbx_element, p_elem, *list) {
  15488. uc->tmp_element_flag[(*p_elem)->element_id] = 0;
  15489. }
  15490. }
  15491. return 1;
  15492. }
  15493. ufbxi_nodiscard ufbxi_noinline static ufbx_element *ufbxi_fetch_dst_element(ufbx_element *element, bool search_node, const char *prop, ufbx_element_type src_type)
  15494. {
  15495. do {
  15496. ufbx_connection_list conns = ufbxi_find_dst_connections(element, prop);
  15497. ufbxi_for_list(ufbx_connection, conn, conns) {
  15498. if (conn->src->type == src_type) {
  15499. return conn->src;
  15500. }
  15501. }
  15502. } while (search_node && (element = ufbxi_get_element_node(element)) != NULL);
  15503. return NULL;
  15504. }
  15505. ufbxi_nodiscard ufbxi_noinline static ufbx_element *ufbxi_fetch_src_element(ufbx_element *element, bool search_node, const char *prop, ufbx_element_type dst_type)
  15506. {
  15507. do {
  15508. ufbx_connection_list conns = ufbxi_find_src_connections(element, prop);
  15509. ufbxi_for_list(ufbx_connection, conn, conns) {
  15510. if (conn->dst->type == dst_type) {
  15511. return conn->dst;
  15512. }
  15513. }
  15514. } while (search_node && (element = ufbxi_get_element_node(element)) != NULL);
  15515. return NULL;
  15516. }
  15517. ufbxi_nodiscard ufbxi_noinline static int ufbxi_fetch_textures(ufbxi_context *uc, ufbx_material_texture_list *list, ufbx_element *element, bool search_node)
  15518. {
  15519. size_t num_textures = 0;
  15520. do {
  15521. ufbxi_for_list(ufbx_connection, conn, element->connections_dst) {
  15522. if (conn->src_prop.length > 0) continue;
  15523. if (conn->src->type == UFBX_ELEMENT_TEXTURE) {
  15524. ufbx_material_texture *tex = ufbxi_push(&uc->tmp_stack, ufbx_material_texture, 1);
  15525. ufbxi_check(tex);
  15526. tex->shader_prop = tex->material_prop = conn->dst_prop;
  15527. tex->texture = (ufbx_texture*)conn->src;
  15528. num_textures++;
  15529. }
  15530. }
  15531. } while (search_node && (element = ufbxi_get_element_node(element)) != NULL);
  15532. list->data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_material_texture, num_textures);
  15533. list->count = num_textures;
  15534. ufbxi_check(list->data);
  15535. return 1;
  15536. }
  15537. ufbxi_nodiscard ufbxi_noinline static int ufbxi_fetch_mesh_materials(ufbxi_context *uc, ufbx_material_list *list, ufbx_element *element, bool search_node)
  15538. {
  15539. size_t num_materials = 0;
  15540. do {
  15541. ufbx_connection_list conns = ufbxi_find_dst_connections(element, NULL);
  15542. ufbxi_for_list(ufbx_connection, conn, conns) {
  15543. if (conn->src->type == UFBX_ELEMENT_MATERIAL) {
  15544. ufbx_material *mat = (ufbx_material*)conn->src;
  15545. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_material*, 1, &mat));
  15546. num_materials++;
  15547. }
  15548. }
  15549. if (num_materials > 0) break;
  15550. } while (search_node && (element = ufbxi_get_element_node(element)) != NULL);
  15551. list->data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_material*, num_materials);
  15552. list->count = num_materials;
  15553. ufbxi_check(list->data);
  15554. return 1;
  15555. }
  15556. ufbxi_nodiscard ufbxi_noinline static int ufbxi_fetch_deformers(ufbxi_context *uc, ufbx_element_list *list, ufbx_element *element, bool search_node)
  15557. {
  15558. size_t num_deformers = 0;
  15559. do {
  15560. ufbxi_for_list(ufbx_connection, conn, element->connections_dst) {
  15561. if (conn->src_prop.length > 0) continue;
  15562. ufbx_element_type type = conn->src->type;
  15563. if (type == UFBX_ELEMENT_SKIN_DEFORMER || type == UFBX_ELEMENT_BLEND_DEFORMER || type == UFBX_ELEMENT_CACHE_DEFORMER) {
  15564. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_element*, 1, &conn->src));
  15565. num_deformers++;
  15566. }
  15567. }
  15568. } while (search_node && (element = ufbxi_get_element_node(element)) != NULL);
  15569. list->data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_element*, num_deformers);
  15570. list->count = num_deformers;
  15571. ufbxi_check(list->data);
  15572. return 1;
  15573. }
  15574. ufbxi_nodiscard ufbxi_noinline static int ufbxi_fetch_blend_keyframes(ufbxi_context *uc, ufbx_blend_keyframe_list *list, ufbx_element *element)
  15575. {
  15576. size_t num_keyframes = 0;
  15577. ufbx_connection_list conns = ufbxi_find_dst_connections(element, NULL);
  15578. ufbxi_for_list(ufbx_connection, conn, conns) {
  15579. if (conn->src->type == UFBX_ELEMENT_BLEND_SHAPE) {
  15580. ufbx_blend_keyframe key = { (ufbx_blend_shape*)conn->src };
  15581. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_blend_keyframe, 1, &key));
  15582. num_keyframes++;
  15583. }
  15584. }
  15585. list->data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_blend_keyframe, num_keyframes);
  15586. list->count = num_keyframes;
  15587. ufbxi_check(list->data);
  15588. return 1;
  15589. }
  15590. ufbxi_nodiscard ufbxi_noinline static int ufbxi_fetch_texture_layers(ufbxi_context *uc, ufbx_texture_layer_list *list, ufbx_element *element)
  15591. {
  15592. size_t num_layers = 0;
  15593. ufbx_connection_list conns = ufbxi_find_dst_connections(element, NULL);
  15594. ufbxi_for_list(ufbx_connection, conn, conns) {
  15595. if (conn->src->type == UFBX_ELEMENT_TEXTURE) {
  15596. ufbx_texture *texture = (ufbx_texture*)conn->src;
  15597. ufbx_texture_layer layer = { texture };
  15598. layer.alpha = ufbxi_find_real(&texture->props, ufbxi_Texture_alpha, 1.0f);
  15599. layer.blend_mode = (ufbx_blend_mode)ufbxi_find_enum(&texture->props, ufbxi_BlendMode, UFBX_BLEND_REPLACE, UFBX_BLEND_OVERLAY);
  15600. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_texture_layer, 1, &layer));
  15601. num_layers++;
  15602. }
  15603. }
  15604. list->data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_texture_layer, num_layers);
  15605. list->count = num_layers;
  15606. ufbxi_check(list->data);
  15607. return 1;
  15608. }
  15609. static ufbxi_forceinline bool ufbxi_prop_connection_less(const ufbx_connection *a, const char *prop)
  15610. {
  15611. int cmp = strcmp(a->dst_prop.data, prop);
  15612. if (cmp != 0) return cmp < 0;
  15613. return a->src_prop.length == 0;
  15614. }
  15615. ufbxi_nodiscard ufbxi_noinline static ufbx_connection *ufbxi_find_prop_connection(const ufbx_element *element, const char *prop)
  15616. {
  15617. if (!prop) prop = ufbxi_empty_char;
  15618. size_t index = SIZE_MAX;
  15619. ufbxi_macro_lower_bound_eq(ufbx_connection, 32, &index,
  15620. element->connections_dst.data, 0, element->connections_dst.count,
  15621. (ufbxi_prop_connection_less(a, prop)),
  15622. (a->dst_prop.data == prop && a->src_prop.length > 0));
  15623. return index < SIZE_MAX ? &element->connections_dst.data[index] : NULL;
  15624. }
  15625. ufbxi_forceinline static void ufbxi_patch_index_pointer(ufbxi_context *uc, uint32_t **p_index)
  15626. {
  15627. if (*p_index == ufbxi_sentinel_index_zero) {
  15628. *p_index = uc->zero_indices;
  15629. } else if (*p_index == ufbxi_sentinel_index_consecutive) {
  15630. *p_index = uc->consecutive_indices;
  15631. }
  15632. }
  15633. ufbxi_nodiscard static bool ufbxi_cmp_anim_prop_less(const ufbx_anim_prop *a, const ufbx_anim_prop *b)
  15634. {
  15635. if (a->element != b->element) return a->element < b->element;
  15636. if (a->_internal_key != b->_internal_key) return a->_internal_key < b->_internal_key;
  15637. return ufbxi_str_less(a->prop_name, b->prop_name);
  15638. }
  15639. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_anim_props(ufbxi_context *uc, ufbx_anim_prop *aprops, size_t count)
  15640. {
  15641. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_anim_prop)));
  15642. ufbxi_macro_stable_sort(ufbx_anim_prop, 32, aprops, uc->tmp_arr, count, ( ufbxi_cmp_anim_prop_less(a, b) ));
  15643. return 1;
  15644. }
  15645. ufbxi_noinline static bool ufbxi_material_texture_less(void *user, const void *va, const void *vb)
  15646. {
  15647. (void)user;
  15648. const ufbx_material_texture *a = (const ufbx_material_texture*)va, *b = (const ufbx_material_texture*)vb;
  15649. return ufbxi_str_less(a->material_prop, b->material_prop);
  15650. }
  15651. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_material_textures(ufbxi_context *uc, ufbx_material_texture *textures, size_t count)
  15652. {
  15653. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_material_texture)));
  15654. ufbxi_stable_sort(sizeof(ufbx_material_texture), 32, textures, uc->tmp_arr, count, &ufbxi_material_texture_less, NULL);
  15655. return 1;
  15656. }
  15657. static ufbxi_noinline bool ufbxi_bone_pose_less(void *user, const void *va, const void *vb)
  15658. {
  15659. (void)user;
  15660. const ufbx_bone_pose *a = (const ufbx_bone_pose *)va, *b = (const ufbx_bone_pose *)vb;
  15661. return a->bone_node->typed_id < b->bone_node->typed_id;
  15662. }
  15663. ufbxi_nodiscard ufbxi_noinline static ufbx_anim_prop *ufbxi_find_anim_prop_start(ufbx_anim_layer *layer, const ufbx_element *element)
  15664. {
  15665. size_t index = SIZE_MAX;
  15666. ufbxi_macro_lower_bound_eq(ufbx_anim_prop, 16, &index, layer->anim_props.data, 0, layer->anim_props.count,
  15667. (a->element < element), (a->element == element));
  15668. return index != SIZE_MAX ? &layer->anim_props.data[index] : NULL;
  15669. }
  15670. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_bone_poses(ufbxi_context *uc, ufbx_pose *pose)
  15671. {
  15672. size_t count = pose->bone_poses.count;
  15673. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, pose->bone_poses.count * sizeof(ufbx_bone_pose)));
  15674. ufbxi_stable_sort(sizeof(ufbx_bone_pose), 16, pose->bone_poses.data, uc->tmp_arr, count, &ufbxi_bone_pose_less, NULL);
  15675. return 1;
  15676. }
  15677. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_skin_weights(ufbxi_context *uc, ufbx_skin_deformer *skin)
  15678. {
  15679. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, skin->max_weights_per_vertex * sizeof(ufbx_skin_weight)));
  15680. for (size_t i = 0; i < skin->vertices.count; i++) {
  15681. ufbx_skin_vertex v = skin->vertices.data[i];
  15682. ufbxi_macro_stable_sort(ufbx_skin_weight, 32, skin->weights.data + v.weight_begin, uc->tmp_arr, v.num_weights,
  15683. ( a->weight > b->weight ));
  15684. }
  15685. return 1;
  15686. }
  15687. ufbxi_noinline static bool ufbxi_blend_keyframe_less(void *user, const void *va, const void *vb)
  15688. {
  15689. (void)user;
  15690. const ufbx_blend_keyframe *a = (const ufbx_blend_keyframe*)va, *b = (const ufbx_blend_keyframe*)vb;
  15691. return a->target_weight < b->target_weight;
  15692. }
  15693. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_blend_keyframes(ufbxi_context *uc, ufbx_blend_keyframe *keyframes, size_t count)
  15694. {
  15695. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbx_blend_keyframe)));
  15696. ufbxi_stable_sort(sizeof(ufbx_blend_keyframe), 32, keyframes, uc->tmp_arr, count, &ufbxi_blend_keyframe_less, NULL);
  15697. return 1;
  15698. }
  15699. // Material tables
  15700. typedef void (*ufbxi_mat_transform_fn)(ufbx_vec4 *a);
  15701. static void ufbxi_mat_transform_invert_x(ufbx_vec4 *v) { v->x = 1.0f - v->x; }
  15702. static void ufbxi_mat_transform_unknown_shininess(ufbx_vec4 *v) { if (v->x >= 0.0f) v->x = (ufbx_real)(1.0f - ufbx_sqrt(v->x) * (ufbx_real)0.1); if (!(v->x >= 0.0f)) v->x = 0.0f; }
  15703. static void ufbxi_mat_transform_blender_opacity(ufbx_vec4 *v) { v->x = 1.0f - v->x; }
  15704. static void ufbxi_mat_transform_blender_shininess(ufbx_vec4 *v) { if (v->x >= 0.0f) v->x = (ufbx_real)(1.0f - ufbx_sqrt(v->x) * (ufbx_real)0.1); if (!(v->x >= 0.0f)) v->x = 0.0f; }
  15705. typedef enum {
  15706. UFBXI_MAT_TRANSFORM_IDENTITY,
  15707. UFBXI_MAT_TRANSFORM_INVERT_X,
  15708. UFBXI_MAT_TRANSFORM_UNKNOWN_SHININESS,
  15709. UFBXI_MAT_TRANSFORM_BLENDER_OPACITY,
  15710. UFBXI_MAT_TRANSFORM_BLENDER_SHININESS,
  15711. UFBXI_MAT_TRANSFORM_COUNT,
  15712. } ufbxi_mat_transform;
  15713. typedef enum {
  15714. // Set `value_vec4.w` (usually alpha) to 1.0 if not defined by the property
  15715. UFBXI_SHADER_MAPPING_DEFAULT_W_1 = 0x1,
  15716. // Widen values to RGB if only a single value is present.
  15717. UFBXI_SHADER_MAPPING_WIDEN_TO_RGB = 0x2,
  15718. } ufbxi_shader_mapping_flag;
  15719. typedef enum {
  15720. // Invert the feature flag
  15721. UFBXI_SHADER_FEATURE_INVERTED = 0x1,
  15722. // Enable the feature if the given property exists
  15723. UFBXI_SHADER_FEATURE_IF_EXISTS = 0x2,
  15724. // Enable the feature if the given property has a texture
  15725. UFBXI_SHADER_FEATURE_IF_TEXTURE = 0x4,
  15726. // Enable if the feature is in [0.5, 1.5], (ie. 2 won't enable this feature)
  15727. UFBXI_SHADER_FEATURE_IF_AROUND_1 = 0x8,
  15728. UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE = UFBXI_SHADER_FEATURE_IF_EXISTS|UFBXI_SHADER_FEATURE_IF_TEXTURE,
  15729. } ufbxi_shader_feature_flag;
  15730. static const ufbxi_mat_transform_fn ufbxi_mat_transform_fns[] = {
  15731. NULL,
  15732. &ufbxi_mat_transform_invert_x,
  15733. &ufbxi_mat_transform_unknown_shininess,
  15734. &ufbxi_mat_transform_blender_opacity,
  15735. &ufbxi_mat_transform_blender_shininess,
  15736. };
  15737. ufbx_static_assert(transform_count, ufbxi_arraycount(ufbxi_mat_transform_fns) == UFBXI_MAT_TRANSFORM_COUNT);
  15738. typedef struct {
  15739. uint8_t index; // < `ufbx_material_(fbx|pbr)_map`
  15740. uint8_t flags; // < Combination of `ufbxi_shader_mapping_flag`
  15741. uint8_t transform; // < `ufbxi_mat_transform`
  15742. uint8_t prop_len; // < Length of `prop` not including NULL terminator
  15743. const char *prop; // < Name of FBX material property or shader mapping
  15744. } ufbxi_shader_mapping;
  15745. typedef struct {
  15746. const ufbxi_shader_mapping *data;
  15747. size_t count;
  15748. const ufbxi_shader_mapping *features;
  15749. size_t feature_count;
  15750. uint32_t default_features;
  15751. ufbx_string texture_prefix;
  15752. ufbx_string texture_suffix;
  15753. ufbx_string texture_enabled_prefix;
  15754. ufbx_string texture_enabled_suffix;
  15755. } ufbxi_shader_mapping_list;
  15756. #define ufbxi_mat_string(str) sizeof(str) - 1, str
  15757. static const ufbxi_shader_mapping ufbxi_base_fbx_mapping[] = {
  15758. { UFBX_MATERIAL_FBX_DIFFUSE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Diffuse") },
  15759. { UFBX_MATERIAL_FBX_DIFFUSE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("DiffuseColor") },
  15760. { UFBX_MATERIAL_FBX_DIFFUSE_FACTOR, 0, 0, ufbxi_mat_string("DiffuseFactor") },
  15761. { UFBX_MATERIAL_FBX_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Specular") },
  15762. { UFBX_MATERIAL_FBX_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("SpecularColor") },
  15763. { UFBX_MATERIAL_FBX_SPECULAR_FACTOR, 0, 0, ufbxi_mat_string("SpecularFactor") },
  15764. { UFBX_MATERIAL_FBX_SPECULAR_EXPONENT, 0, 0, ufbxi_mat_string("Shininess") },
  15765. { UFBX_MATERIAL_FBX_SPECULAR_EXPONENT, 0, 0, ufbxi_mat_string("ShininessExponent") },
  15766. { UFBX_MATERIAL_FBX_REFLECTION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Reflection") },
  15767. { UFBX_MATERIAL_FBX_REFLECTION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("ReflectionColor") },
  15768. { UFBX_MATERIAL_FBX_REFLECTION_FACTOR, 0, 0, ufbxi_mat_string("ReflectionFactor") },
  15769. { UFBX_MATERIAL_FBX_TRANSPARENCY_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Transparent") },
  15770. { UFBX_MATERIAL_FBX_TRANSPARENCY_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("TransparentColor") },
  15771. { UFBX_MATERIAL_FBX_TRANSPARENCY_FACTOR, 0, 0, ufbxi_mat_string("TransparentFactor") },
  15772. { UFBX_MATERIAL_FBX_TRANSPARENCY_FACTOR, 0, 0, ufbxi_mat_string("TransparencyFactor") },
  15773. { UFBX_MATERIAL_FBX_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Emissive") },
  15774. { UFBX_MATERIAL_FBX_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("EmissiveColor") },
  15775. { UFBX_MATERIAL_FBX_EMISSION_FACTOR, 0, 0, ufbxi_mat_string("EmissiveFactor") },
  15776. { UFBX_MATERIAL_FBX_AMBIENT_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Ambient") },
  15777. { UFBX_MATERIAL_FBX_AMBIENT_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("AmbientColor") },
  15778. { UFBX_MATERIAL_FBX_AMBIENT_FACTOR, 0, 0, ufbxi_mat_string("AmbientFactor") },
  15779. { UFBX_MATERIAL_FBX_NORMAL_MAP, 0, 0, ufbxi_mat_string("NormalMap") },
  15780. { UFBX_MATERIAL_FBX_BUMP, 0, 0, ufbxi_mat_string("Bump") },
  15781. { UFBX_MATERIAL_FBX_BUMP_FACTOR, 0, 0, ufbxi_mat_string("BumpFactor") },
  15782. { UFBX_MATERIAL_FBX_DISPLACEMENT, 0, 0, ufbxi_mat_string("Displacement") },
  15783. { UFBX_MATERIAL_FBX_DISPLACEMENT_FACTOR, 0, 0, ufbxi_mat_string("DisplacementFactor") },
  15784. { UFBX_MATERIAL_FBX_VECTOR_DISPLACEMENT, 0, 0, ufbxi_mat_string("VectorDisplacement") },
  15785. { UFBX_MATERIAL_FBX_VECTOR_DISPLACEMENT_FACTOR, 0, 0, ufbxi_mat_string("VectorDisplacementFactor") },
  15786. };
  15787. static const ufbxi_shader_mapping ufbxi_obj_fbx_mapping[] = {
  15788. { UFBX_MATERIAL_FBX_AMBIENT_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1|UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("Ka") },
  15789. { UFBX_MATERIAL_FBX_DIFFUSE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1|UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("Kd") },
  15790. { UFBX_MATERIAL_FBX_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1|UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("Ks") },
  15791. { UFBX_MATERIAL_FBX_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1|UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("Ke") },
  15792. { UFBX_MATERIAL_FBX_SPECULAR_EXPONENT, 0, 0, ufbxi_mat_string("Ns") },
  15793. { UFBX_MATERIAL_FBX_TRANSPARENCY_FACTOR, 0, UFBXI_MAT_TRANSFORM_INVERT_X, ufbxi_mat_string("d") },
  15794. { UFBX_MATERIAL_FBX_NORMAL_MAP, 0, 0, ufbxi_mat_string("norm") },
  15795. { UFBX_MATERIAL_FBX_DISPLACEMENT, 0, 0, ufbxi_mat_string("disp") },
  15796. { UFBX_MATERIAL_FBX_BUMP, 0, 0, ufbxi_mat_string("bump") },
  15797. };
  15798. static const ufbxi_shader_mapping ufbxi_fbx_lambert_shader_pbr_mapping[] = {
  15799. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Diffuse") },
  15800. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("DiffuseColor") },
  15801. { UFBX_MATERIAL_PBR_BASE_FACTOR, 0, 0, ufbxi_mat_string("DiffuseFactor") },
  15802. { UFBX_MATERIAL_PBR_TRANSMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Transparent") },
  15803. { UFBX_MATERIAL_PBR_TRANSMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("TransparentColor") },
  15804. { UFBX_MATERIAL_PBR_TRANSMISSION_FACTOR, 0, 0, ufbxi_mat_string("TransparentFactor") },
  15805. { UFBX_MATERIAL_PBR_TRANSMISSION_FACTOR, 0, 0, ufbxi_mat_string("TransparencyFactor") },
  15806. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Emissive") },
  15807. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("EmissiveColor") },
  15808. { UFBX_MATERIAL_PBR_EMISSION_FACTOR, 0, 0, ufbxi_mat_string("EmissiveFactor") },
  15809. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("NormalMap") },
  15810. };
  15811. static const ufbxi_shader_mapping ufbxi_fbx_phong_shader_pbr_mapping[] = {
  15812. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Diffuse") },
  15813. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("DiffuseColor") },
  15814. { UFBX_MATERIAL_PBR_BASE_FACTOR, 0, 0, ufbxi_mat_string("DiffuseFactor") },
  15815. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Specular") },
  15816. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("SpecularColor") },
  15817. { UFBX_MATERIAL_PBR_SPECULAR_FACTOR, 0, 0, ufbxi_mat_string("SpecularFactor") },
  15818. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, UFBXI_MAT_TRANSFORM_UNKNOWN_SHININESS, ufbxi_mat_string("Shininess") },
  15819. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, UFBXI_MAT_TRANSFORM_UNKNOWN_SHININESS, ufbxi_mat_string("ShininessExponent") },
  15820. { UFBX_MATERIAL_PBR_TRANSMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Transparent") },
  15821. { UFBX_MATERIAL_PBR_TRANSMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("TransparentColor") },
  15822. { UFBX_MATERIAL_PBR_TRANSMISSION_FACTOR, 0, 0, ufbxi_mat_string("TransparentFactor") },
  15823. { UFBX_MATERIAL_PBR_TRANSMISSION_FACTOR, 0, 0, ufbxi_mat_string("TransparencyFactor") },
  15824. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Emissive") },
  15825. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("EmissiveColor") },
  15826. { UFBX_MATERIAL_PBR_EMISSION_FACTOR, 0, 0, ufbxi_mat_string("EmissiveFactor") },
  15827. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("NormalMap") },
  15828. };
  15829. static const ufbxi_shader_mapping ufbxi_osl_standard_shader_pbr_mapping[] = {
  15830. { UFBX_MATERIAL_PBR_BASE_FACTOR, 0, 0, ufbxi_mat_string("base") },
  15831. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("base_color") },
  15832. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, 0, ufbxi_mat_string("specular_roughness") },
  15833. { UFBX_MATERIAL_PBR_DIFFUSE_ROUGHNESS, 0, 0, ufbxi_mat_string("diffuse_roughness") },
  15834. { UFBX_MATERIAL_PBR_METALNESS, 0, 0, ufbxi_mat_string("metalness") },
  15835. { UFBX_MATERIAL_PBR_SPECULAR_FACTOR, 0, 0, ufbxi_mat_string("specular") },
  15836. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("specular_color") },
  15837. { UFBX_MATERIAL_PBR_SPECULAR_IOR, 0, 0, ufbxi_mat_string("specular_IOR") },
  15838. { UFBX_MATERIAL_PBR_SPECULAR_ANISOTROPY, 0, 0, ufbxi_mat_string("specular_anisotropy") },
  15839. { UFBX_MATERIAL_PBR_SPECULAR_ROTATION, 0, 0, ufbxi_mat_string("specular_rotation") },
  15840. { UFBX_MATERIAL_PBR_TRANSMISSION_FACTOR, 0, 0, ufbxi_mat_string("transmission") },
  15841. { UFBX_MATERIAL_PBR_TRANSMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("transmission_color") },
  15842. { UFBX_MATERIAL_PBR_TRANSMISSION_DEPTH, 0, 0, ufbxi_mat_string("transmission_depth") },
  15843. { UFBX_MATERIAL_PBR_TRANSMISSION_SCATTER, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("transmission_scatter") },
  15844. { UFBX_MATERIAL_PBR_TRANSMISSION_SCATTER_ANISOTROPY, 0, 0, ufbxi_mat_string("transmission_scatter_anisotropy") },
  15845. { UFBX_MATERIAL_PBR_TRANSMISSION_DISPERSION, 0, 0, ufbxi_mat_string("transmission_dispersion") },
  15846. { UFBX_MATERIAL_PBR_TRANSMISSION_EXTRA_ROUGHNESS, 0, 0, ufbxi_mat_string("transmission_extra_roughness") },
  15847. { UFBX_MATERIAL_PBR_SUBSURFACE_FACTOR, 0, 0, ufbxi_mat_string("subsurface") },
  15848. { UFBX_MATERIAL_PBR_SUBSURFACE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("subsurface_color") },
  15849. { UFBX_MATERIAL_PBR_SUBSURFACE_RADIUS, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("subsurface_radius") },
  15850. { UFBX_MATERIAL_PBR_SUBSURFACE_SCALE, 0, 0, ufbxi_mat_string("subsurface_scale") },
  15851. { UFBX_MATERIAL_PBR_SUBSURFACE_ANISOTROPY, 0, 0, ufbxi_mat_string("subsurface_anisotropy") },
  15852. { UFBX_MATERIAL_PBR_SHEEN_FACTOR, 0, 0, ufbxi_mat_string("sheen") },
  15853. { UFBX_MATERIAL_PBR_SHEEN_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("sheen_color") },
  15854. { UFBX_MATERIAL_PBR_SHEEN_ROUGHNESS, 0, 0, ufbxi_mat_string("sheen_roughness") },
  15855. { UFBX_MATERIAL_PBR_COAT_FACTOR, 0, 0, ufbxi_mat_string("coat") },
  15856. { UFBX_MATERIAL_PBR_COAT_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("coat_color") },
  15857. { UFBX_MATERIAL_PBR_COAT_ROUGHNESS, 0, 0, ufbxi_mat_string("coat_roughness") },
  15858. { UFBX_MATERIAL_PBR_COAT_IOR, 0, 0, ufbxi_mat_string("coat_IOR") },
  15859. { UFBX_MATERIAL_PBR_COAT_ANISOTROPY, 0, 0, ufbxi_mat_string("coat_anisotropy") },
  15860. { UFBX_MATERIAL_PBR_COAT_ROTATION, 0, 0, ufbxi_mat_string("coat_rotation") },
  15861. { UFBX_MATERIAL_PBR_COAT_NORMAL, 0, 0, ufbxi_mat_string("coat_normal") },
  15862. { UFBX_MATERIAL_PBR_COAT_AFFECT_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("coat_affect_color") },
  15863. { UFBX_MATERIAL_PBR_COAT_AFFECT_BASE_ROUGHNESS, 0, 0, ufbxi_mat_string("coat_affect_roughness") },
  15864. { UFBX_MATERIAL_PBR_THIN_FILM_THICKNESS, 0, 0, ufbxi_mat_string("thin_film_thickness") },
  15865. { UFBX_MATERIAL_PBR_THIN_FILM_IOR, 0, 0, ufbxi_mat_string("thin_film_IOR") },
  15866. { UFBX_MATERIAL_PBR_EMISSION_FACTOR, 0, 0, ufbxi_mat_string("emission") },
  15867. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("emission_color") },
  15868. { UFBX_MATERIAL_PBR_OPACITY, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("opacity") },
  15869. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("NormalMap") },
  15870. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("normalCamera") },
  15871. { UFBX_MATERIAL_PBR_TANGENT_MAP, 0, 0, ufbxi_mat_string("tangent") },
  15872. };
  15873. static const ufbxi_shader_mapping ufbxi_osl_standard_shader_features[] = {
  15874. { UFBX_MATERIAL_FEATURE_THIN_WALLED, 0, 0, ufbxi_mat_string("thin_walled") },
  15875. };
  15876. static const ufbxi_shader_mapping ufbxi_arnold_shader_pbr_mapping[] = {
  15877. { UFBX_MATERIAL_PBR_BASE_FACTOR, 0, 0, ufbxi_mat_string("base") },
  15878. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("baseColor") },
  15879. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, 0, ufbxi_mat_string("specularRoughness") },
  15880. { UFBX_MATERIAL_PBR_DIFFUSE_ROUGHNESS, 0, 0, ufbxi_mat_string("diffuseRoughness") },
  15881. { UFBX_MATERIAL_PBR_METALNESS, 0, 0, ufbxi_mat_string("metalness") },
  15882. { UFBX_MATERIAL_PBR_SPECULAR_FACTOR, 0, 0, ufbxi_mat_string("specular") },
  15883. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("specularColor") },
  15884. { UFBX_MATERIAL_PBR_SPECULAR_IOR, 0, 0, ufbxi_mat_string("specularIOR") },
  15885. { UFBX_MATERIAL_PBR_SPECULAR_ANISOTROPY, 0, 0, ufbxi_mat_string("specularAnisotropy") },
  15886. { UFBX_MATERIAL_PBR_SPECULAR_ROTATION, 0, 0, ufbxi_mat_string("specularRotation") },
  15887. { UFBX_MATERIAL_PBR_TRANSMISSION_FACTOR, 0, 0, ufbxi_mat_string("transmission") },
  15888. { UFBX_MATERIAL_PBR_TRANSMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("transmissionColor") },
  15889. { UFBX_MATERIAL_PBR_TRANSMISSION_DEPTH, 0, 0, ufbxi_mat_string("transmissionDepth") },
  15890. { UFBX_MATERIAL_PBR_TRANSMISSION_SCATTER, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("transmissionScatter") },
  15891. { UFBX_MATERIAL_PBR_TRANSMISSION_SCATTER_ANISOTROPY, 0, 0, ufbxi_mat_string("transmissionScatterAnisotropy") },
  15892. { UFBX_MATERIAL_PBR_TRANSMISSION_DISPERSION, 0, 0, ufbxi_mat_string("transmissionDispersion") },
  15893. { UFBX_MATERIAL_PBR_TRANSMISSION_EXTRA_ROUGHNESS, 0, 0, ufbxi_mat_string("transmissionExtraRoughness") },
  15894. { UFBX_MATERIAL_PBR_SUBSURFACE_FACTOR, 0, 0, ufbxi_mat_string("subsurface") },
  15895. { UFBX_MATERIAL_PBR_SUBSURFACE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("subsurfaceColor") },
  15896. { UFBX_MATERIAL_PBR_SUBSURFACE_RADIUS, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("subsurfaceRadius") },
  15897. { UFBX_MATERIAL_PBR_SUBSURFACE_SCALE, 0, 0, ufbxi_mat_string("subsurfaceScale") },
  15898. { UFBX_MATERIAL_PBR_SUBSURFACE_ANISOTROPY, 0, 0, ufbxi_mat_string("subsurfaceAnisotropy") },
  15899. { UFBX_MATERIAL_PBR_SHEEN_FACTOR, 0, 0, ufbxi_mat_string("sheen") },
  15900. { UFBX_MATERIAL_PBR_SHEEN_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("sheenColor") },
  15901. { UFBX_MATERIAL_PBR_SHEEN_ROUGHNESS, 0, 0, ufbxi_mat_string("sheenRoughness") },
  15902. { UFBX_MATERIAL_PBR_COAT_FACTOR, 0, 0, ufbxi_mat_string("coat") },
  15903. { UFBX_MATERIAL_PBR_COAT_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("coatColor") },
  15904. { UFBX_MATERIAL_PBR_COAT_ROUGHNESS, 0, 0, ufbxi_mat_string("coatRoughness") },
  15905. { UFBX_MATERIAL_PBR_COAT_IOR, 0, 0, ufbxi_mat_string("coatIOR") },
  15906. { UFBX_MATERIAL_PBR_COAT_ANISOTROPY, 0, 0, ufbxi_mat_string("coatAnisotropy") },
  15907. { UFBX_MATERIAL_PBR_COAT_ROTATION, 0, 0, ufbxi_mat_string("coatRotation") },
  15908. { UFBX_MATERIAL_PBR_COAT_NORMAL, 0, 0, ufbxi_mat_string("coatNormal") },
  15909. { UFBX_MATERIAL_PBR_THIN_FILM_THICKNESS, 0, 0, ufbxi_mat_string("thinFilmThickness") },
  15910. { UFBX_MATERIAL_PBR_THIN_FILM_IOR, 0, 0, ufbxi_mat_string("thinFilmIOR") },
  15911. { UFBX_MATERIAL_PBR_EMISSION_FACTOR, 0, 0, ufbxi_mat_string("emission") },
  15912. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("emissionColor") },
  15913. { UFBX_MATERIAL_PBR_OPACITY, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("opacity") },
  15914. { UFBX_MATERIAL_PBR_INDIRECT_DIFFUSE, 0, 0, ufbxi_mat_string("indirectDiffuse") },
  15915. { UFBX_MATERIAL_PBR_INDIRECT_SPECULAR, 0, 0, ufbxi_mat_string("indirectSpecular") },
  15916. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("NormalMap") },
  15917. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("normalCamera") },
  15918. { UFBX_MATERIAL_PBR_TANGENT_MAP, 0, 0, ufbxi_mat_string("tangent") },
  15919. { UFBX_MATERIAL_PBR_MATTE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("aiMatteColor") },
  15920. { UFBX_MATERIAL_PBR_MATTE_FACTOR, 0, 0, ufbxi_mat_string("aiMatteColorA") },
  15921. { UFBX_MATERIAL_PBR_SUBSURFACE_TYPE, 0, 0, ufbxi_mat_string("subsurfaceType") },
  15922. { UFBX_MATERIAL_PBR_TRANSMISSION_PRIORITY, 0, 0, ufbxi_mat_string("dielectricPriority") },
  15923. { UFBX_MATERIAL_PBR_TRANSMISSION_ENABLE_IN_AOV, 0, 0, ufbxi_mat_string("transmitAovs") },
  15924. };
  15925. static const ufbxi_shader_mapping ufbxi_arnold_shader_features[] = {
  15926. { UFBX_MATERIAL_FEATURE_MATTE, 0, 0, ufbxi_mat_string("aiEnableMatte") },
  15927. { UFBX_MATERIAL_FEATURE_THIN_WALLED, 0, 0, ufbxi_mat_string("thinWalled") },
  15928. { UFBX_MATERIAL_FEATURE_CAUSTICS, 0, 0, ufbxi_mat_string("caustics") },
  15929. { UFBX_MATERIAL_FEATURE_INTERNAL_REFLECTIONS, 0, 0, ufbxi_mat_string("internalReflections") },
  15930. { UFBX_MATERIAL_FEATURE_EXIT_TO_BACKGROUND, 0, 0, ufbxi_mat_string("exitToBackground") },
  15931. };
  15932. static const ufbxi_shader_mapping ufbxi_3ds_max_physical_material_pbr_mapping[] = {
  15933. { UFBX_MATERIAL_PBR_BASE_FACTOR, 0, 0, ufbxi_mat_string("base_weight") },
  15934. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("base_color") },
  15935. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, 0, ufbxi_mat_string("roughness") },
  15936. { UFBX_MATERIAL_PBR_DIFFUSE_ROUGHNESS, 0, 0, ufbxi_mat_string("diff_rough") },
  15937. { UFBX_MATERIAL_PBR_DIFFUSE_ROUGHNESS, 0, 0, ufbxi_mat_string("diff_roughness") },
  15938. { UFBX_MATERIAL_PBR_METALNESS, 0, 0, ufbxi_mat_string("metalness") },
  15939. { UFBX_MATERIAL_PBR_SPECULAR_FACTOR, 0, 0, ufbxi_mat_string("reflectivity") },
  15940. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("refl_color") },
  15941. { UFBX_MATERIAL_PBR_SPECULAR_ANISOTROPY, 0, 0, ufbxi_mat_string("anisotropy") },
  15942. { UFBX_MATERIAL_PBR_SPECULAR_ROTATION, 0, 0, ufbxi_mat_string("aniso_angle") },
  15943. { UFBX_MATERIAL_PBR_SPECULAR_ROTATION, 0, 0, ufbxi_mat_string("anisoangle") },
  15944. { UFBX_MATERIAL_PBR_SPECULAR_IOR, 0, 0, ufbxi_mat_string("trans_ior") }, // NOTE: Not a typo, IOR is same for transparency/specular
  15945. { UFBX_MATERIAL_PBR_TRANSMISSION_FACTOR, 0, 0, ufbxi_mat_string("transparency") },
  15946. { UFBX_MATERIAL_PBR_TRANSMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("trans_color") },
  15947. { UFBX_MATERIAL_PBR_TRANSMISSION_DEPTH, 0, 0, ufbxi_mat_string("trans_depth") },
  15948. { UFBX_MATERIAL_PBR_TRANSMISSION_ROUGHNESS, 0, 0, ufbxi_mat_string("trans_rough") },
  15949. { UFBX_MATERIAL_PBR_TRANSMISSION_ROUGHNESS, 0, 0, ufbxi_mat_string("trans_roughness") },
  15950. { UFBX_MATERIAL_PBR_SUBSURFACE_FACTOR, 0, 0, ufbxi_mat_string("scattering") },
  15951. { UFBX_MATERIAL_PBR_SUBSURFACE_TINT_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("sss_color") },
  15952. { UFBX_MATERIAL_PBR_SUBSURFACE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("sss_scatter_color") },
  15953. { UFBX_MATERIAL_PBR_SUBSURFACE_RADIUS, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("sss_depth") },
  15954. { UFBX_MATERIAL_PBR_SUBSURFACE_SCALE, 0, 0, ufbxi_mat_string("sss_scale") },
  15955. { UFBX_MATERIAL_PBR_COAT_FACTOR, 0, 0, ufbxi_mat_string("coat") },
  15956. { UFBX_MATERIAL_PBR_COAT_FACTOR, 0, 0, ufbxi_mat_string("coating") },
  15957. { UFBX_MATERIAL_PBR_COAT_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("coat_color") },
  15958. { UFBX_MATERIAL_PBR_COAT_ROUGHNESS, 0, 0, ufbxi_mat_string("coat_rough") },
  15959. { UFBX_MATERIAL_PBR_COAT_ROUGHNESS, 0, 0, ufbxi_mat_string("coat_roughness") },
  15960. { UFBX_MATERIAL_PBR_COAT_IOR, 0, 0, ufbxi_mat_string("coat_ior") },
  15961. { UFBX_MATERIAL_PBR_COAT_NORMAL, 0, 0, ufbxi_mat_string("coat_bump") },
  15962. { UFBX_MATERIAL_PBR_COAT_NORMAL, 0, 0, ufbxi_mat_string("clearcoat_bump_map_amt") },
  15963. { UFBX_MATERIAL_PBR_COAT_AFFECT_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("coat_affect_color") },
  15964. { UFBX_MATERIAL_PBR_COAT_AFFECT_BASE_ROUGHNESS, 0, 0, ufbxi_mat_string("coat_affect_roughness") },
  15965. { UFBX_MATERIAL_PBR_EMISSION_FACTOR, 0, 0, ufbxi_mat_string("emission") },
  15966. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("emit_color") },
  15967. { UFBX_MATERIAL_PBR_OPACITY, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("cutout") },
  15968. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("bump") },
  15969. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("bump_map_amt") },
  15970. { UFBX_MATERIAL_PBR_DISPLACEMENT_MAP, 0, 0, ufbxi_mat_string("displacement") },
  15971. { UFBX_MATERIAL_PBR_DISPLACEMENT_MAP, 0, 0, ufbxi_mat_string("displacement_map_amt") },
  15972. { UFBX_MATERIAL_PBR_SUBSURFACE_TYPE, 0, 0, ufbxi_mat_string("subsurfaceType") },
  15973. };
  15974. static const ufbxi_shader_mapping ufbxi_3ds_max_physical_material_features[] = {
  15975. { UFBX_MATERIAL_FEATURE_THIN_WALLED, 0, 0, ufbxi_mat_string("thin_walled") },
  15976. { UFBX_MATERIAL_FEATURE_SPECULAR, 0, 0, ufbxi_mat_string("material_mode") },
  15977. { UFBX_MATERIAL_FEATURE_DIFFUSE_ROUGHNESS, 0, 0, ufbxi_mat_string("material_mode") },
  15978. { UFBX_MATERIAL_FEATURE_TRANSMISSION_ROUGHNESS, UFBXI_SHADER_FEATURE_INVERTED, 0, ufbxi_mat_string("trans_roughness_lock") },
  15979. { UFBX_MATERIAL_FEATURE_ROUGHNESS_AS_GLOSSINESS, 0, 0, ufbxi_mat_string("roughness_inv") },
  15980. { UFBX_MATERIAL_FEATURE_TRANSMISSION_ROUGHNESS_AS_GLOSSINESS, 0, 0, ufbxi_mat_string("trans_roughness_inv") },
  15981. { UFBX_MATERIAL_FEATURE_COAT_ROUGHNESS_AS_GLOSSINESS, 0, 0, ufbxi_mat_string("coat_roughness_inv") },
  15982. };
  15983. static const ufbxi_shader_mapping ufbxi_gltf_material_pbr_mapping[] = {
  15984. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("main|baseColor") },
  15985. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, 0, ufbxi_mat_string("main|roughness") },
  15986. { UFBX_MATERIAL_PBR_METALNESS, 0, 0, ufbxi_mat_string("main|metalness") },
  15987. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("main|normal") },
  15988. { UFBX_MATERIAL_PBR_AMBIENT_OCCLUSION, 0, 0, ufbxi_mat_string("main|ambientOcclusion") },
  15989. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("main|emission") },
  15990. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("main|emissionColor") },
  15991. { UFBX_MATERIAL_PBR_OPACITY, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("main|Alpha") },
  15992. { UFBX_MATERIAL_PBR_COAT_FACTOR, 0, 0, ufbxi_mat_string("extension|clearcoat") },
  15993. { UFBX_MATERIAL_PBR_COAT_ROUGHNESS, 0, 0, ufbxi_mat_string("extension|clearcoatRoughness") },
  15994. { UFBX_MATERIAL_PBR_COAT_NORMAL, 0, 0, ufbxi_mat_string("extension|clearcoatNormal") },
  15995. { UFBX_MATERIAL_PBR_SHEEN_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("extension|sheenColor") },
  15996. { UFBX_MATERIAL_PBR_SHEEN_ROUGHNESS, 0, 0, ufbxi_mat_string("extension|sheenRoughness") },
  15997. { UFBX_MATERIAL_PBR_SPECULAR_FACTOR, 0, 0, ufbxi_mat_string("extension|specular") },
  15998. { UFBX_MATERIAL_PBR_SPECULAR_FACTOR, 0, 0, ufbxi_mat_string("extension|Specular") },
  15999. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("extension|specularcolor") },
  16000. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("extension|specularColor") },
  16001. { UFBX_MATERIAL_PBR_TRANSMISSION_FACTOR, 0, 0, ufbxi_mat_string("extension|transmission") },
  16002. { UFBX_MATERIAL_PBR_SPECULAR_IOR, 0, 0, ufbxi_mat_string("extension|indexOfRefraction") },
  16003. };
  16004. static const ufbxi_shader_mapping ufbxi_3ds_max_pbr_metal_rough_pbr_mapping[] = {
  16005. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("base_color") },
  16006. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("baseColor") },
  16007. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, 0, ufbxi_mat_string("roughness") },
  16008. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, 0, ufbxi_mat_string("Roughness_Map") },
  16009. { UFBX_MATERIAL_PBR_METALNESS, 0, 0, ufbxi_mat_string("metalness") },
  16010. { UFBX_MATERIAL_PBR_AMBIENT_OCCLUSION, 0, 0, ufbxi_mat_string("ao") },
  16011. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("norm") },
  16012. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("emit_color") },
  16013. { UFBX_MATERIAL_PBR_DISPLACEMENT_MAP, 0, 0, ufbxi_mat_string("displacement") },
  16014. { UFBX_MATERIAL_PBR_DISPLACEMENT_MAP, 0, 0, ufbxi_mat_string("displacement_amt") },
  16015. { UFBX_MATERIAL_PBR_OPACITY, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("opacity") },
  16016. };
  16017. static const ufbxi_shader_mapping ufbxi_3ds_max_pbr_spec_gloss_pbr_mapping[] = {
  16018. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("base_color") },
  16019. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("baseColor") },
  16020. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("Specular") },
  16021. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("specular") },
  16022. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, 0, ufbxi_mat_string("glossiness") },
  16023. { UFBX_MATERIAL_PBR_AMBIENT_OCCLUSION, 0, 0, ufbxi_mat_string("ao") },
  16024. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("norm") },
  16025. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("emit_color") },
  16026. { UFBX_MATERIAL_PBR_DISPLACEMENT_MAP, 0, 0, ufbxi_mat_string("displacement") },
  16027. { UFBX_MATERIAL_PBR_DISPLACEMENT_MAP, 0, 0, ufbxi_mat_string("displacement_amt") },
  16028. { UFBX_MATERIAL_PBR_OPACITY, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("opacity") },
  16029. };
  16030. static const ufbxi_shader_mapping ufbxi_3ds_max_pbr_features[] = {
  16031. { UFBX_MATERIAL_FEATURE_ROUGHNESS_AS_GLOSSINESS, UFBXI_SHADER_FEATURE_IF_AROUND_1, 0, ufbxi_mat_string("useGlossiness") },
  16032. };
  16033. static const ufbxi_shader_mapping ufbxi_gltf_material_features[] = {
  16034. { UFBX_MATERIAL_FEATURE_DOUBLE_SIDED, 0, 0, ufbxi_mat_string("main|DoubleSided") },
  16035. { UFBX_MATERIAL_FEATURE_SHEEN, 0, 0, ufbxi_mat_string("extension|enableSheen") },
  16036. { UFBX_MATERIAL_FEATURE_COAT, 0, 0, ufbxi_mat_string("extension|enableClearCoat") },
  16037. { UFBX_MATERIAL_FEATURE_TRANSMISSION, 0, 0, ufbxi_mat_string("extension|enableTransmission") },
  16038. { UFBX_MATERIAL_FEATURE_IOR, 0, 0, ufbxi_mat_string("extension|enableIndexOfRefraction") },
  16039. { UFBX_MATERIAL_FEATURE_SPECULAR, 0, 0, ufbxi_mat_string("extension|enableSpecular") },
  16040. { UFBX_MATERIAL_FEATURE_UNLIT, 0, 0, ufbxi_mat_string("extension|unlit") },
  16041. };
  16042. // NOTE: These are just the names used by the standard PBS "preset".
  16043. // In _theory_ we could walk ShaderGraph but that's a bit out of scope for ufbx.
  16044. static const ufbxi_shader_mapping ufbxi_shaderfx_graph_pbr_mapping[] = {
  16045. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("color") },
  16046. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("base_color") },
  16047. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, 0, ufbxi_mat_string("roughness") },
  16048. { UFBX_MATERIAL_PBR_METALNESS, 0, 0, ufbxi_mat_string("metallic") },
  16049. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("normal") },
  16050. { UFBX_MATERIAL_PBR_EMISSION_FACTOR, 0, 0, ufbxi_mat_string("emissive_intensity") },
  16051. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("emissive") },
  16052. { UFBX_MATERIAL_PBR_AMBIENT_OCCLUSION, 0, 0, ufbxi_mat_string("ao") },
  16053. };
  16054. static const ufbxi_shader_mapping ufbxi_blender_phong_shader_pbr_mapping[] = {
  16055. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("DiffuseColor") },
  16056. { UFBX_MATERIAL_PBR_OPACITY, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, UFBXI_MAT_TRANSFORM_BLENDER_OPACITY, ufbxi_mat_string("TransparencyFactor") },
  16057. { UFBX_MATERIAL_PBR_EMISSION_FACTOR, 0, 0, ufbxi_mat_string("EmissiveFactor") },
  16058. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1, 0, ufbxi_mat_string("EmissiveColor") },
  16059. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, UFBXI_MAT_TRANSFORM_BLENDER_SHININESS, ufbxi_mat_string("Shininess") },
  16060. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, UFBXI_MAT_TRANSFORM_BLENDER_SHININESS, ufbxi_mat_string("ShininessExponent") },
  16061. { UFBX_MATERIAL_PBR_METALNESS, 0, 0, ufbxi_mat_string("ReflectionFactor") },
  16062. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("NormalMap") },
  16063. };
  16064. static const ufbxi_shader_mapping ufbxi_obj_pbr_mapping[] = {
  16065. { UFBX_MATERIAL_PBR_BASE_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1|UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("Kd") },
  16066. { UFBX_MATERIAL_PBR_SPECULAR_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1|UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("Ks") },
  16067. { UFBX_MATERIAL_PBR_EMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1|UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("Ke") },
  16068. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, UFBXI_MAT_TRANSFORM_UNKNOWN_SHININESS, ufbxi_mat_string("Ns") },
  16069. { UFBX_MATERIAL_PBR_ROUGHNESS, 0, 0, ufbxi_mat_string("Pr") },
  16070. { UFBX_MATERIAL_PBR_SPECULAR_IOR, 0, 0, ufbxi_mat_string("Ni") },
  16071. { UFBX_MATERIAL_PBR_METALNESS, 0, 0, ufbxi_mat_string("Pm") },
  16072. { UFBX_MATERIAL_PBR_OPACITY, UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("d") },
  16073. { UFBX_MATERIAL_PBR_TRANSMISSION_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1|UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("Tf") },
  16074. { UFBX_MATERIAL_PBR_DISPLACEMENT_MAP, 0, 0, ufbxi_mat_string("disp") },
  16075. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("bump") },
  16076. { UFBX_MATERIAL_PBR_NORMAL_MAP, 0, 0, ufbxi_mat_string("norm") },
  16077. { UFBX_MATERIAL_PBR_SHEEN_COLOR, UFBXI_SHADER_MAPPING_DEFAULT_W_1|UFBXI_SHADER_MAPPING_WIDEN_TO_RGB, 0, ufbxi_mat_string("Ps") },
  16078. { UFBX_MATERIAL_PBR_COAT_FACTOR, 0, 0, ufbxi_mat_string("Pc") },
  16079. { UFBX_MATERIAL_PBR_COAT_ROUGHNESS, 0, 0, ufbxi_mat_string("Pcr") },
  16080. { UFBX_MATERIAL_PBR_SPECULAR_ANISOTROPY, 0, 0, ufbxi_mat_string("aniso") },
  16081. { UFBX_MATERIAL_PBR_SPECULAR_ROTATION, 0, 0, ufbxi_mat_string("anisor") },
  16082. };
  16083. static const ufbxi_shader_mapping ufbxi_obj_features[] = {
  16084. { UFBX_MATERIAL_FEATURE_PBR, UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE, 0, ufbxi_mat_string("Pr") },
  16085. { UFBX_MATERIAL_FEATURE_PBR, UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE, 0, ufbxi_mat_string("Pm") },
  16086. { UFBX_MATERIAL_FEATURE_SHEEN, UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE, 0, ufbxi_mat_string("Ps") },
  16087. { UFBX_MATERIAL_FEATURE_COAT, UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE, 0, ufbxi_mat_string("Pc") },
  16088. { UFBX_MATERIAL_FEATURE_METALNESS, UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE, 0, ufbxi_mat_string("Pm") },
  16089. { UFBX_MATERIAL_FEATURE_IOR, UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE, 0, ufbxi_mat_string("Ni") },
  16090. { UFBX_MATERIAL_FEATURE_OPACITY, UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE, 0, ufbxi_mat_string("d") },
  16091. { UFBX_MATERIAL_FEATURE_TRANSMISSION, UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE, 0, ufbxi_mat_string("Tf") },
  16092. { UFBX_MATERIAL_FEATURE_EMISSION, UFBXI_SHADER_FEATURE_IF_EXISTS_OR_TEXTURE, 0, ufbxi_mat_string("Ke") },
  16093. };
  16094. enum {
  16095. UFBXI_MAT_PBR = 1 << UFBX_MATERIAL_FEATURE_PBR,
  16096. UFBXI_MAT_METALNESS = 1 << UFBX_MATERIAL_FEATURE_METALNESS,
  16097. UFBXI_MAT_DIFFUSE = 1 << UFBX_MATERIAL_FEATURE_DIFFUSE,
  16098. UFBXI_MAT_SPECULAR = 1 << UFBX_MATERIAL_FEATURE_SPECULAR,
  16099. UFBXI_MAT_EMISSION = 1 << UFBX_MATERIAL_FEATURE_EMISSION,
  16100. UFBXI_MAT_COAT = 1 << UFBX_MATERIAL_FEATURE_COAT,
  16101. UFBXI_MAT_SHEEN = 1 << UFBX_MATERIAL_FEATURE_SHEEN,
  16102. UFBXI_MAT_TRANSMISSION = 1 << UFBX_MATERIAL_FEATURE_TRANSMISSION,
  16103. UFBXI_MAT_OPACITY = 1 << UFBX_MATERIAL_FEATURE_OPACITY,
  16104. UFBXI_MAT_AMBIENT_OCCLUSION = 1 << UFBX_MATERIAL_FEATURE_AMBIENT_OCCLUSION,
  16105. UFBXI_MAT_MATTE = 1 << UFBX_MATERIAL_FEATURE_MATTE,
  16106. UFBXI_MAT_UNLIT = 1 << UFBX_MATERIAL_FEATURE_UNLIT,
  16107. UFBXI_MAT_IOR = 1 << UFBX_MATERIAL_FEATURE_IOR,
  16108. UFBXI_MAT_DIFFUSE_ROUGHNESS = 1 << UFBX_MATERIAL_FEATURE_DIFFUSE_ROUGHNESS,
  16109. UFBXI_MAT_TRANSMISSION_ROUGHNESS = 1 << UFBX_MATERIAL_FEATURE_TRANSMISSION_ROUGHNESS,
  16110. UFBXI_MAT_THIN_WALLED = 1 << UFBX_MATERIAL_FEATURE_THIN_WALLED,
  16111. UFBXI_MAT_CAUSTICS = 1 << UFBX_MATERIAL_FEATURE_CAUSTICS,
  16112. UFBXI_MAT_EXIT_TO_BACKGROUND = 1 << UFBX_MATERIAL_FEATURE_EXIT_TO_BACKGROUND,
  16113. UFBXI_MAT_INTERNAL_REFLECTIONS = 1 << UFBX_MATERIAL_FEATURE_INTERNAL_REFLECTIONS,
  16114. UFBXI_MAT_DOUBLE_SIDED = 1 << UFBX_MATERIAL_FEATURE_DOUBLE_SIDED,
  16115. };
  16116. static const ufbxi_shader_mapping_list ufbxi_shader_pbr_mappings[] = {
  16117. { // UFBX_SHADER_UNKNOWN
  16118. ufbxi_fbx_phong_shader_pbr_mapping, ufbxi_arraycount(ufbxi_fbx_phong_shader_pbr_mapping),
  16119. NULL, 0,
  16120. (uint32_t)(UFBXI_MAT_DIFFUSE | UFBXI_MAT_SPECULAR | UFBXI_MAT_EMISSION | UFBXI_MAT_TRANSMISSION),
  16121. },
  16122. { // UFBX_SHADER_FBX_LAMBERT
  16123. ufbxi_fbx_lambert_shader_pbr_mapping, ufbxi_arraycount(ufbxi_fbx_lambert_shader_pbr_mapping),
  16124. NULL, 0,
  16125. (uint32_t)(UFBXI_MAT_DIFFUSE | UFBXI_MAT_EMISSION | UFBXI_MAT_TRANSMISSION),
  16126. },
  16127. { // UFBX_SHADER_FBX_PHONG
  16128. ufbxi_fbx_phong_shader_pbr_mapping, ufbxi_arraycount(ufbxi_fbx_phong_shader_pbr_mapping),
  16129. NULL, 0,
  16130. (uint32_t)(UFBXI_MAT_DIFFUSE | UFBXI_MAT_SPECULAR | UFBXI_MAT_EMISSION | UFBXI_MAT_TRANSMISSION),
  16131. },
  16132. { // UFBX_SHADER_OSL_STANDARD_SURFACE
  16133. ufbxi_osl_standard_shader_pbr_mapping, ufbxi_arraycount(ufbxi_osl_standard_shader_pbr_mapping),
  16134. ufbxi_osl_standard_shader_features, ufbxi_arraycount(ufbxi_osl_standard_shader_features),
  16135. (uint32_t)(UFBXI_MAT_PBR | UFBXI_MAT_METALNESS | UFBXI_MAT_DIFFUSE | UFBXI_MAT_SPECULAR | UFBXI_MAT_COAT
  16136. | UFBXI_MAT_SHEEN | UFBXI_MAT_TRANSMISSION | UFBXI_MAT_OPACITY | UFBXI_MAT_IOR | UFBXI_MAT_DIFFUSE_ROUGHNESS),
  16137. },
  16138. { // UFBX_SHADER_ARNOLD_STANDARD_SURFACE
  16139. ufbxi_arnold_shader_pbr_mapping, ufbxi_arraycount(ufbxi_arnold_shader_pbr_mapping),
  16140. ufbxi_arnold_shader_features, ufbxi_arraycount(ufbxi_arnold_shader_features),
  16141. (uint32_t)(UFBXI_MAT_PBR | UFBXI_MAT_METALNESS | UFBXI_MAT_DIFFUSE | UFBXI_MAT_SPECULAR | UFBXI_MAT_COAT
  16142. | UFBXI_MAT_SHEEN | UFBXI_MAT_TRANSMISSION | UFBXI_MAT_OPACITY | UFBXI_MAT_IOR | UFBXI_MAT_DIFFUSE_ROUGHNESS),
  16143. },
  16144. { // UFBX_SHADER_3DS_MAX_PHYSICAL_MATERIAL
  16145. ufbxi_3ds_max_physical_material_pbr_mapping, ufbxi_arraycount(ufbxi_3ds_max_physical_material_pbr_mapping),
  16146. ufbxi_3ds_max_physical_material_features, ufbxi_arraycount(ufbxi_3ds_max_physical_material_features),
  16147. (uint32_t)(UFBXI_MAT_PBR | UFBXI_MAT_METALNESS | UFBXI_MAT_DIFFUSE | UFBXI_MAT_COAT
  16148. | UFBXI_MAT_SHEEN | UFBXI_MAT_TRANSMISSION | UFBXI_MAT_OPACITY | UFBXI_MAT_IOR),
  16149. { NULL, 0 }, ufbxi_string_literal("_map"), // texture_prefix/suffix
  16150. { NULL, 0 }, ufbxi_string_literal("_map_on"), // texture_enabled_prefix/suffix
  16151. },
  16152. { // UFBX_SHADER_3DS_MAX_PBR_METAL_ROUGH
  16153. ufbxi_3ds_max_pbr_metal_rough_pbr_mapping, ufbxi_arraycount(ufbxi_3ds_max_pbr_metal_rough_pbr_mapping),
  16154. ufbxi_3ds_max_pbr_features, ufbxi_arraycount(ufbxi_3ds_max_pbr_features),
  16155. (uint32_t)(UFBXI_MAT_PBR | UFBXI_MAT_METALNESS | UFBXI_MAT_DIFFUSE | UFBXI_MAT_OPACITY),
  16156. { NULL, 0 }, ufbxi_string_literal("_map"), // texture_prefix/suffix
  16157. { NULL, 0 }, { NULL, 0 }, // texture_enabled_prefix/suffix
  16158. },
  16159. { // UFBX_SHADER_3DS_MAX_PBR_SPEC_GLOSS
  16160. ufbxi_3ds_max_pbr_spec_gloss_pbr_mapping, ufbxi_arraycount(ufbxi_3ds_max_pbr_spec_gloss_pbr_mapping),
  16161. ufbxi_3ds_max_pbr_features, ufbxi_arraycount(ufbxi_3ds_max_pbr_features),
  16162. (uint32_t)(UFBXI_MAT_PBR | UFBXI_MAT_SPECULAR | UFBXI_MAT_DIFFUSE | UFBXI_MAT_OPACITY),
  16163. { NULL, 0 }, ufbxi_string_literal("_map"), // texture_prefix/suffix
  16164. { NULL, 0 }, { NULL, 0 }, // texture_enabled_prefix/suffix
  16165. },
  16166. { // UFBX_SHADER_GLTF_MATERIAL
  16167. ufbxi_gltf_material_pbr_mapping, ufbxi_arraycount(ufbxi_gltf_material_pbr_mapping),
  16168. ufbxi_gltf_material_features, ufbxi_arraycount(ufbxi_gltf_material_features),
  16169. (uint32_t)(UFBXI_MAT_PBR | UFBXI_MAT_METALNESS | UFBXI_MAT_DIFFUSE | UFBXI_MAT_EMISSION | UFBXI_MAT_OPACITY | UFBXI_MAT_AMBIENT_OCCLUSION),
  16170. { NULL, 0 }, ufbxi_string_literal("Map"), // texture_prefix/suffix
  16171. { NULL, 0 }, { NULL, 0 }, // texture_enabled_prefix/suffix
  16172. },
  16173. { // UFBX_SHADER_SHADERFX_GRAPH
  16174. ufbxi_shaderfx_graph_pbr_mapping, ufbxi_arraycount(ufbxi_shaderfx_graph_pbr_mapping),
  16175. NULL, 0,
  16176. (uint32_t)(UFBXI_MAT_PBR | UFBXI_MAT_METALNESS | UFBXI_MAT_DIFFUSE | UFBXI_MAT_EMISSION | UFBXI_MAT_AMBIENT_OCCLUSION),
  16177. ufbxi_string_literal("TEX_"), ufbxi_string_literal("_map"), // texture_prefix/suffix
  16178. ufbxi_string_literal("use_"), ufbxi_string_literal("_map"), // texture_enabled_prefix/suffix
  16179. },
  16180. { // UFBX_SHADER_BLENDER_PHONG
  16181. ufbxi_blender_phong_shader_pbr_mapping, ufbxi_arraycount(ufbxi_blender_phong_shader_pbr_mapping),
  16182. NULL, 0,
  16183. (uint32_t)(UFBXI_MAT_PBR | UFBXI_MAT_METALNESS | UFBXI_MAT_DIFFUSE | UFBXI_MAT_EMISSION),
  16184. },
  16185. { // UFBX_SHADER_WAVEFRONT_MTL
  16186. ufbxi_obj_pbr_mapping, ufbxi_arraycount(ufbxi_obj_pbr_mapping),
  16187. ufbxi_obj_features, ufbxi_arraycount(ufbxi_obj_features),
  16188. (uint32_t)(UFBXI_MAT_DIFFUSE | UFBXI_MAT_SPECULAR),
  16189. },
  16190. };
  16191. ufbx_static_assert(shader_pbr_mapping_list, ufbxi_arraycount(ufbxi_shader_pbr_mappings) == UFBX_SHADER_TYPE_COUNT);
  16192. enum {
  16193. UFBXI_MAPPING_FETCH_VALUE = 0x1,
  16194. UFBXI_MAPPING_FETCH_TEXTURE = 0x2,
  16195. UFBXI_MAPPING_FETCH_TEXTURE_ENABLED = 0x4,
  16196. UFBXI_MAPPING_FETCH_FEATURE = 0x8,
  16197. };
  16198. ufbxi_noinline static void ufbxi_fetch_mapping_maps(ufbx_material *material, ufbx_material_map *maps, ufbx_material_feature_info *features,
  16199. ufbx_shader *shader, const ufbxi_shader_mapping *mappings, size_t count, ufbx_string prefix, ufbx_string prefix2, ufbx_string suffix, uint32_t flags)
  16200. {
  16201. char combined_name[512];
  16202. ufbx_shader_prop_binding identity_binding;
  16203. ufbxi_for(const ufbxi_shader_mapping, mapping, mappings, count) {
  16204. ufbx_string prop_name = { mapping->prop, mapping->prop_len };
  16205. if (prefix.length > 0 || prefix2.length > 0 || suffix.length > 0) {
  16206. if (prop_name.length + prefix.length + prefix2.length + suffix.length <= sizeof(combined_name)) {
  16207. char *dst = combined_name;
  16208. if (prefix.length > 0) {
  16209. memcpy(dst, prefix.data, prefix.length);
  16210. dst += prefix.length;
  16211. }
  16212. if (prefix2.length > 0) {
  16213. memcpy(dst, prefix2.data, prefix2.length);
  16214. dst += prefix2.length;
  16215. }
  16216. if (prop_name.length > 0) {
  16217. memcpy(dst, prop_name.data, prop_name.length);
  16218. dst += prop_name.length;
  16219. }
  16220. if (suffix.length > 0) {
  16221. memcpy(dst, suffix.data, suffix.length);
  16222. dst += suffix.length;
  16223. }
  16224. prop_name.data = combined_name;
  16225. prop_name.length = ufbxi_to_size(dst - combined_name);
  16226. }
  16227. }
  16228. ufbx_shader_prop_binding_list bindings = ufbx_find_shader_prop_bindings_len(shader, prop_name.data, prop_name.length);
  16229. if (bindings.count == 0) {
  16230. identity_binding.material_prop = prop_name;
  16231. identity_binding.shader_prop = ufbx_empty_string;
  16232. bindings.data = &identity_binding;
  16233. bindings.count = 1;
  16234. }
  16235. uint32_t mapping_flags = mapping->flags;
  16236. ufbxi_for_list(ufbx_shader_prop_binding, binding, bindings) {
  16237. ufbx_string name = binding->material_prop;
  16238. ufbx_prop *prop = ufbx_find_prop_len(&material->props, name.data, name.length);
  16239. if (flags & UFBXI_MAPPING_FETCH_FEATURE) {
  16240. ufbx_material_feature_info *feature = &features[mapping->index];
  16241. if (prop && prop->type != UFBX_PROP_REFERENCE) {
  16242. feature->enabled = prop->value_int != 0;
  16243. feature->is_explicit = true;
  16244. if (mapping_flags & UFBXI_SHADER_FEATURE_IF_AROUND_1) {
  16245. feature->enabled = (prop->value_real >= 0.5f && prop->value_real <= 1.5f);
  16246. }
  16247. if (mapping_flags & UFBXI_SHADER_FEATURE_INVERTED) {
  16248. feature->enabled = !feature->enabled;
  16249. }
  16250. if (mapping_flags & UFBXI_SHADER_FEATURE_IF_EXISTS) {
  16251. feature->enabled = true;
  16252. }
  16253. }
  16254. if (mapping_flags & UFBXI_SHADER_FEATURE_IF_TEXTURE) {
  16255. ufbx_texture *texture = ufbx_find_prop_texture_len(material, name.data, name.length);
  16256. if (texture) {
  16257. feature->enabled = true;
  16258. }
  16259. }
  16260. continue;
  16261. }
  16262. ufbx_material_map *map = &maps[mapping->index];
  16263. if (flags & UFBXI_MAPPING_FETCH_VALUE) {
  16264. if (prop && prop->type != UFBX_PROP_REFERENCE) {
  16265. map->value_vec4 = prop->value_vec4;
  16266. map->value_int = prop->value_int;
  16267. map->has_value = true;
  16268. if (mapping->transform) {
  16269. ufbxi_mat_transform_fn transform_fn = ufbxi_mat_transform_fns[mapping->transform];
  16270. transform_fn(&map->value_vec4);
  16271. }
  16272. uint32_t prop_flags = (uint32_t)prop->flags;
  16273. if ((mapping->flags & UFBXI_SHADER_MAPPING_DEFAULT_W_1) != 0 && (prop_flags & UFBX_PROP_FLAG_VALUE_VEC4) == 0) {
  16274. map->value_vec4.w = 1.0f;
  16275. }
  16276. if ((mapping->flags & UFBXI_SHADER_MAPPING_WIDEN_TO_RGB) != 0 && (prop_flags & UFBX_PROP_FLAG_VALUE_REAL) != 0) {
  16277. map->value_vec3.y = map->value_vec3.x;
  16278. map->value_vec3.z = map->value_vec3.x;
  16279. }
  16280. if ((prop_flags & UFBX_PROP_FLAG_VALUE_REAL) != 0) {
  16281. map->value_components = 1;
  16282. } else if ((prop_flags & UFBX_PROP_FLAG_VALUE_VEC2) != 0) {
  16283. map->value_components = 2;
  16284. } else if ((prop_flags & UFBX_PROP_FLAG_VALUE_VEC3) != 0) {
  16285. map->value_components = 3;
  16286. } else if ((prop_flags & UFBX_PROP_FLAG_VALUE_VEC4) != 0) {
  16287. map->value_components = 4;
  16288. } else {
  16289. map->value_components = 0;
  16290. }
  16291. }
  16292. }
  16293. if (flags & UFBXI_MAPPING_FETCH_TEXTURE) {
  16294. ufbx_texture *texture = ufbx_find_prop_texture_len(material, name.data, name.length);
  16295. if (texture) {
  16296. map->texture = texture;
  16297. map->texture_enabled = true;
  16298. }
  16299. }
  16300. if (flags & UFBXI_MAPPING_FETCH_TEXTURE_ENABLED) {
  16301. if (prop) {
  16302. map->texture_enabled = prop->value_int != 0;
  16303. }
  16304. }
  16305. }
  16306. }
  16307. }
  16308. ufbxi_noinline static void ufbxi_update_factor(ufbx_material_map *factor_map, ufbx_material_map *color_map)
  16309. {
  16310. if (!factor_map->has_value) {
  16311. if (color_map->has_value && !ufbxi_is_vec4_zero(color_map->value_vec4)) {
  16312. factor_map->value_real = 1.0f;
  16313. factor_map->value_int = 1;
  16314. } else {
  16315. factor_map->value_real = 0.0f;
  16316. factor_map->value_int = 0;
  16317. }
  16318. }
  16319. }
  16320. // Some material modes have toggleable roughness/glossiness mode, we read it initially
  16321. // always as roughness and if a matching feature such as `roughness_as_glossiness` is set
  16322. // we transfer the data into the glossiness and invert the roughness.
  16323. typedef struct {
  16324. uint8_t feature;
  16325. uint8_t roughness_map;
  16326. uint8_t glossiness_map;
  16327. } ufbxi_glossiness_remap;
  16328. static const ufbxi_glossiness_remap ufbxi_glossiness_remaps[] = {
  16329. { UFBX_MATERIAL_FEATURE_ROUGHNESS_AS_GLOSSINESS, UFBX_MATERIAL_PBR_ROUGHNESS, UFBX_MATERIAL_PBR_GLOSSINESS },
  16330. { UFBX_MATERIAL_FEATURE_COAT_ROUGHNESS_AS_GLOSSINESS, UFBX_MATERIAL_PBR_COAT_ROUGHNESS, UFBX_MATERIAL_PBR_COAT_GLOSSINESS },
  16331. { UFBX_MATERIAL_FEATURE_TRANSMISSION_ROUGHNESS_AS_GLOSSINESS, UFBX_MATERIAL_PBR_TRANSMISSION_ROUGHNESS, UFBX_MATERIAL_PBR_TRANSMISSION_GLOSSINESS },
  16332. };
  16333. ufbxi_noinline static void ufbxi_fetch_maps(ufbx_scene *scene, ufbx_material *material)
  16334. {
  16335. (void)scene;
  16336. ufbx_shader *shader = material->shader;
  16337. ufbx_assert((uint32_t)material->shader_type < UFBX_SHADER_TYPE_COUNT);
  16338. memset(&material->fbx, 0, sizeof(material->fbx));
  16339. memset(&material->pbr, 0, sizeof(material->pbr));
  16340. memset(&material->features, 0, sizeof(material->features));
  16341. const ufbxi_shader_mapping *base_mapping = ufbxi_base_fbx_mapping;
  16342. size_t num_base_mapping = ufbxi_arraycount(ufbxi_base_fbx_mapping);
  16343. if (scene->metadata.file_format == UFBX_FILE_FORMAT_OBJ || scene->metadata.file_format == UFBX_FILE_FORMAT_MTL) {
  16344. base_mapping = ufbxi_obj_fbx_mapping;
  16345. num_base_mapping = ufbxi_arraycount(ufbxi_obj_fbx_mapping);
  16346. }
  16347. ufbxi_fetch_mapping_maps(material, material->fbx.maps, NULL, NULL,
  16348. base_mapping, num_base_mapping,
  16349. ufbx_empty_string, ufbx_empty_string, ufbx_empty_string,
  16350. UFBXI_MAPPING_FETCH_VALUE | UFBXI_MAPPING_FETCH_TEXTURE);
  16351. ufbxi_shader_mapping_list list = ufbxi_shader_pbr_mappings[material->shader_type];
  16352. for (uint32_t i = 0; i < UFBX_MATERIAL_FEATURE_COUNT; i++) {
  16353. if ((list.default_features & (1u << i)) != 0) {
  16354. material->features.features[i].enabled = true;
  16355. }
  16356. }
  16357. ufbx_string prefix = ufbx_empty_string;
  16358. if (!shader) {
  16359. prefix = material->shader_prop_prefix;
  16360. }
  16361. if (list.texture_prefix.length > 0 || list.texture_suffix.length > 0) {
  16362. ufbxi_fetch_mapping_maps(material, material->pbr.maps, NULL, shader,
  16363. list.data, list.count, prefix, list.texture_prefix, list.texture_suffix,
  16364. UFBXI_MAPPING_FETCH_TEXTURE);
  16365. }
  16366. ufbxi_fetch_mapping_maps(material, material->pbr.maps, NULL, shader,
  16367. list.data, list.count, prefix, ufbx_empty_string, ufbx_empty_string,
  16368. UFBXI_MAPPING_FETCH_VALUE | UFBXI_MAPPING_FETCH_TEXTURE);
  16369. if (list.texture_enabled_prefix.length > 0 || list.texture_enabled_suffix.length > 0) {
  16370. ufbxi_fetch_mapping_maps(material, material->pbr.maps, NULL, shader,
  16371. list.data, list.count, prefix, list.texture_enabled_prefix, list.texture_enabled_suffix,
  16372. UFBXI_MAPPING_FETCH_TEXTURE_ENABLED);
  16373. }
  16374. ufbxi_fetch_mapping_maps(material, NULL, material->features.features, shader,
  16375. list.features, list.feature_count, prefix, ufbx_empty_string, ufbx_empty_string,
  16376. UFBXI_MAPPING_FETCH_FEATURE);
  16377. ufbxi_update_factor(&material->fbx.diffuse_factor, &material->fbx.diffuse_color);
  16378. ufbxi_update_factor(&material->fbx.specular_factor, &material->fbx.specular_color);
  16379. ufbxi_update_factor(&material->fbx.reflection_factor, &material->fbx.reflection_color);
  16380. ufbxi_update_factor(&material->fbx.transparency_factor, &material->fbx.transparency_color);
  16381. ufbxi_update_factor(&material->fbx.emission_factor, &material->fbx.emission_color);
  16382. ufbxi_update_factor(&material->fbx.ambient_factor, &material->fbx.ambient_color);
  16383. ufbxi_update_factor(&material->pbr.base_factor, &material->pbr.base_color);
  16384. ufbxi_update_factor(&material->pbr.specular_factor, &material->pbr.specular_color);
  16385. ufbxi_update_factor(&material->pbr.emission_factor, &material->pbr.emission_color);
  16386. ufbxi_update_factor(&material->pbr.sheen_factor, &material->pbr.sheen_color);
  16387. ufbxi_update_factor(&material->pbr.transmission_factor, &material->pbr.transmission_color);
  16388. // Patch transmission roughness if only extra roughness is defined
  16389. if (!material->pbr.transmission_roughness.has_value && material->pbr.roughness.has_value && material->pbr.transmission_extra_roughness.has_value) {
  16390. material->pbr.transmission_roughness.value_real = material->pbr.roughness.value_real + material->pbr.transmission_extra_roughness.value_real;
  16391. }
  16392. // Map roughness to glossiness and vice versa
  16393. ufbxi_for(const ufbxi_glossiness_remap, remap, ufbxi_glossiness_remaps, ufbxi_arraycount(ufbxi_glossiness_remaps)) {
  16394. ufbx_material_map *roughness = &material->pbr.maps[remap->roughness_map];
  16395. ufbx_material_map *glossiness = &material->pbr.maps[remap->glossiness_map];
  16396. if (material->features.features[remap->feature].enabled) {
  16397. *glossiness = *roughness;
  16398. memset(roughness, 0, sizeof(ufbx_material_map));
  16399. if (glossiness->has_value) {
  16400. roughness->value_real = 1.0f - glossiness->value_real;
  16401. }
  16402. } else {
  16403. if (roughness->has_value) {
  16404. glossiness->value_real = 1.0f - roughness->value_real;
  16405. }
  16406. }
  16407. }
  16408. }
  16409. typedef enum {
  16410. UFBXI_CONSTRAINT_PROP_NODE,
  16411. UFBXI_CONSTRAINT_PROP_IK_EFFECTOR,
  16412. UFBXI_CONSTRAINT_PROP_IK_END_NODE,
  16413. UFBXI_CONSTRAINT_PROP_AIM_UP,
  16414. UFBXI_CONSTRAINT_PROP_TARGET,
  16415. } ufbxi_constraint_prop_type;
  16416. typedef struct {
  16417. ufbxi_constraint_prop_type type;
  16418. const char *name;
  16419. } ufbxi_constraint_prop;
  16420. static const ufbxi_constraint_prop ufbxi_constraint_props[] = {
  16421. { UFBXI_CONSTRAINT_PROP_NODE, "Constrained Object" },
  16422. { UFBXI_CONSTRAINT_PROP_NODE, "Constrained object (Child)" },
  16423. { UFBXI_CONSTRAINT_PROP_NODE, "First Joint" },
  16424. { UFBXI_CONSTRAINT_PROP_TARGET, "Source" },
  16425. { UFBXI_CONSTRAINT_PROP_TARGET, "Source (Parent)" },
  16426. { UFBXI_CONSTRAINT_PROP_TARGET, "Aim At Object" },
  16427. { UFBXI_CONSTRAINT_PROP_TARGET, "Pole Vector Object" },
  16428. { UFBXI_CONSTRAINT_PROP_IK_EFFECTOR, "Effector" },
  16429. { UFBXI_CONSTRAINT_PROP_IK_END_NODE, "End Joint" },
  16430. { UFBXI_CONSTRAINT_PROP_AIM_UP, "World Up Object" },
  16431. };
  16432. ufbxi_nodiscard ufbxi_noinline static int ufbxi_add_constraint_prop(ufbxi_context *uc, ufbx_constraint *constraint, ufbx_node *node, const char *prop)
  16433. {
  16434. ufbxi_for(const ufbxi_constraint_prop, cprop, ufbxi_constraint_props, ufbxi_arraycount(ufbxi_constraint_props)) {
  16435. if (strcmp(cprop->name, prop) != 0) continue;
  16436. switch (cprop->type) {
  16437. case UFBXI_CONSTRAINT_PROP_NODE: constraint->node = node; break;
  16438. case UFBXI_CONSTRAINT_PROP_IK_EFFECTOR: constraint->ik_effector = node; break;
  16439. case UFBXI_CONSTRAINT_PROP_IK_END_NODE: constraint->ik_end_node = node; break;
  16440. case UFBXI_CONSTRAINT_PROP_AIM_UP: constraint->aim_up_node = node; break;
  16441. case UFBXI_CONSTRAINT_PROP_TARGET: {
  16442. ufbx_constraint_target *target = ufbxi_push_zero(&uc->tmp_stack, ufbx_constraint_target, 1);
  16443. ufbxi_check(target);
  16444. target->node = node;
  16445. target->weight = 1.0f;
  16446. target->transform = ufbx_identity_transform;
  16447. } break;
  16448. default:
  16449. ufbxi_unreachable("Unexpected constraint prop");
  16450. }
  16451. }
  16452. return 1;
  16453. }
  16454. ufbxi_nodiscard ufbxi_noinline static int ufbxi_finalize_nurbs_basis(ufbxi_context *uc, ufbx_nurbs_basis *basis)
  16455. {
  16456. if (basis->topology == UFBX_NURBS_TOPOLOGY_CLOSED) {
  16457. basis->num_wrap_control_points = 1;
  16458. } else if (basis->topology == UFBX_NURBS_TOPOLOGY_PERIODIC) {
  16459. basis->num_wrap_control_points = basis->order - 1;
  16460. } else {
  16461. basis->num_wrap_control_points = 0;
  16462. }
  16463. if (basis->order > 1) {
  16464. size_t degree = basis->order - 1;
  16465. ufbx_real_list knots = basis->knot_vector;
  16466. if (knots.count >= 2*degree + 1) {
  16467. basis->t_min = knots.data[degree];
  16468. basis->t_max = knots.data[knots.count - degree - 1];
  16469. size_t max_spans = knots.count - 2*degree;
  16470. ufbx_real *spans = ufbxi_push(&uc->result, ufbx_real, max_spans);
  16471. ufbxi_check(spans);
  16472. ufbx_real prev = -UFBX_INFINITY;
  16473. size_t num_spans = 0;
  16474. for (size_t i = 0; i < max_spans; i++) {
  16475. ufbx_real t = knots.data[degree + i];
  16476. if (t != prev) {
  16477. spans[num_spans++] = t;
  16478. prev = t;
  16479. }
  16480. }
  16481. basis->spans.data = spans;
  16482. basis->spans.count = num_spans;
  16483. basis->valid = true;
  16484. for (size_t i = 1; i < knots.count; i++) {
  16485. if (knots.data[i - 1] > knots.data[i]) {
  16486. basis->valid = false;
  16487. break;
  16488. }
  16489. }
  16490. }
  16491. }
  16492. return 1;
  16493. }
  16494. ufbxi_nodiscard ufbxi_noinline static int ufbxi_finalize_lod_group(ufbxi_context *uc, ufbx_lod_group *lod)
  16495. {
  16496. size_t num_levels = 0;
  16497. for (size_t i = 0; i < lod->instances.count; i++) {
  16498. num_levels = ufbxi_max_sz(num_levels, lod->instances.data[0]->children.count);
  16499. }
  16500. char prop_name[64];
  16501. for (size_t i = 0; ; i++) {
  16502. int len = ufbxi_snprintf(prop_name, sizeof(prop_name), "Thresholds|Level%zu", i);
  16503. ufbx_prop *prop = ufbx_find_prop_len(&lod->props, prop_name, (size_t)len);
  16504. if (!prop) break;
  16505. num_levels = ufbxi_max_sz(num_levels, i + 1);
  16506. }
  16507. ufbx_lod_level *levels = ufbxi_push_zero(&uc->result, ufbx_lod_level, num_levels);
  16508. ufbxi_check(levels);
  16509. lod->relative_distances = ufbx_find_bool(&lod->props, "ThresholdsUsedAsPercentage", false);
  16510. lod->ignore_parent_transform = !ufbx_find_bool(&lod->props, "WorldSpace", true);
  16511. lod->use_distance_limit = ufbx_find_bool(&lod->props, "MinMaxDistance", false);
  16512. lod->distance_limit_min = ufbx_find_real(&lod->props, "MinDistance", (ufbx_real)-100.0);
  16513. lod->distance_limit_max = ufbx_find_real(&lod->props, "MaxDistance", (ufbx_real)100.0);
  16514. lod->lod_levels.data = levels;
  16515. lod->lod_levels.count = num_levels;
  16516. for (size_t i = 0; i < num_levels; i++) {
  16517. ufbx_lod_level *level = &levels[i];
  16518. if (i > 0) {
  16519. int len = ufbxi_snprintf(prop_name, sizeof(prop_name), "Thresholds|Level%zu", i - 1);
  16520. level->distance = ufbx_find_real_len(&lod->props, prop_name, (size_t)len, 0.0f);
  16521. } else if (lod->relative_distances) {
  16522. level->distance = (ufbx_real)100.0;
  16523. }
  16524. {
  16525. int len = ufbxi_snprintf(prop_name, sizeof(prop_name), "DisplayLevels|Level%zu", i);
  16526. int64_t display = ufbx_find_int_len(&lod->props, prop_name, (size_t)len, 0);
  16527. if (display >= 0 && display <= 2) {
  16528. level->display = (ufbx_lod_display)display;
  16529. }
  16530. }
  16531. }
  16532. return 1;
  16533. }
  16534. ufbxi_nodiscard ufbxi_noinline static int ufbxi_generate_normals(ufbxi_context *uc, ufbx_mesh *mesh)
  16535. {
  16536. size_t num_indices = mesh->num_indices;
  16537. mesh->generated_normals = true;
  16538. ufbx_topo_edge *topo = ufbxi_push(&uc->tmp_stack, ufbx_topo_edge, num_indices);
  16539. ufbxi_check(topo);
  16540. uint32_t *normal_indices = ufbxi_push(&uc->result, uint32_t, num_indices);
  16541. ufbxi_check(normal_indices);
  16542. ufbx_compute_topology(mesh, topo, num_indices);
  16543. size_t num_normals = ufbx_generate_normal_mapping(mesh, topo, num_indices, normal_indices, num_indices, false);
  16544. if (num_normals == mesh->num_vertices) {
  16545. mesh->vertex_normal.unique_per_vertex = true;
  16546. }
  16547. ufbx_vec3 *normal_data = ufbxi_push(&uc->result, ufbx_vec3, num_normals + 1);
  16548. ufbxi_check(normal_data);
  16549. normal_data[0] = ufbx_zero_vec3;
  16550. normal_data++;
  16551. ufbx_compute_normals(mesh, &mesh->vertex_position, normal_indices, num_indices, normal_data, num_normals);
  16552. mesh->vertex_normal.exists = true;
  16553. mesh->vertex_normal.values.data = normal_data;
  16554. mesh->vertex_normal.values.count = num_normals;
  16555. mesh->vertex_normal.indices.data = normal_indices;
  16556. mesh->vertex_normal.indices.count = num_indices;
  16557. mesh->vertex_normal.value_reals = 3;
  16558. mesh->skinned_normal = mesh->vertex_normal;
  16559. ufbxi_pop(&uc->tmp_stack, ufbx_topo_edge, num_indices, NULL);
  16560. return 1;
  16561. }
  16562. ufbxi_nodiscard ufbxi_noinline static int ufbxi_push_prop_prefix(ufbxi_context *uc, ufbx_string *dst, ufbx_string prefix)
  16563. {
  16564. size_t stack_size = 0;
  16565. if (prefix.length > 0 && prefix.data[prefix.length - 1] != '|') {
  16566. stack_size = prefix.length + 1;
  16567. char *copy = ufbxi_push(&uc->tmp_stack, char, stack_size);
  16568. ufbxi_check(copy);
  16569. memcpy(copy, prefix.data, prefix.length);
  16570. copy[prefix.length] = '|';
  16571. prefix.data = copy;
  16572. prefix.length += 1;
  16573. }
  16574. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &prefix, false));
  16575. *dst = prefix;
  16576. if (stack_size > 0) {
  16577. ufbxi_pop(&uc->tmp_stack, char, stack_size, NULL);
  16578. }
  16579. return 1;
  16580. }
  16581. ufbxi_nodiscard ufbxi_noinline static int ufbxi_shader_texture_find_prefix(ufbxi_context *uc, ufbx_texture *texture, ufbx_shader_texture *shader)
  16582. {
  16583. ufbx_string suffixes[3];
  16584. size_t num_suffixes = 0;
  16585. suffixes[num_suffixes++] = ufbxi_str_c(" Parameters/Connections");
  16586. if (shader->shader_name.length > 0) {
  16587. suffixes[num_suffixes++] = shader->shader_name;
  16588. }
  16589. suffixes[num_suffixes++] = ufbxi_str_c("3dsMax|parameters");
  16590. ufbx_assert(num_suffixes <= ufbxi_arraycount(suffixes));
  16591. ufbxi_for(ufbx_string, p_suffix, suffixes, num_suffixes) {
  16592. ufbx_string suffix = *p_suffix;
  16593. ufbxi_for_list(ufbx_prop, prop, texture->props.props) {
  16594. if (prop->type != UFBX_PROP_COMPOUND) continue;
  16595. if (ufbxi_ends_with(prop->name, suffix)) {
  16596. ufbxi_check(ufbxi_push_prop_prefix(uc, &shader->prop_prefix, prop->name));
  16597. return 1;
  16598. }
  16599. }
  16600. }
  16601. // Pre-7000 files don't have explicit Compound properties, so let's look for
  16602. // any property that has the suffix before the last `|` ...
  16603. ufbxi_for(ufbx_string, p_suffix, suffixes, num_suffixes) {
  16604. ufbx_string suffix = *p_suffix;
  16605. ufbxi_for_list(ufbx_prop, prop, texture->props.props) {
  16606. ufbx_string name = prop->name;
  16607. while (name.length > 0) {
  16608. if (name.data[name.length - 1] == '|') {
  16609. break;
  16610. }
  16611. name.length--;
  16612. }
  16613. if (name.length <= 1) continue;
  16614. name.length--;
  16615. if (ufbxi_ends_with(name, suffix)) {
  16616. ufbxi_check(ufbxi_push_prop_prefix(uc, &shader->prop_prefix, name));
  16617. return 1;
  16618. }
  16619. }
  16620. }
  16621. return 1;
  16622. }
  16623. typedef struct {
  16624. uint64_t shader_id;
  16625. const char *shader_name;
  16626. const char *input_name;
  16627. } ufbxi_file_shader;
  16628. // Known shaders that represent sampled images.
  16629. static const ufbxi_file_shader ufbxi_file_shaders[] = {
  16630. { UINT64_C(0x7e73161fad53b12a), "ai_image", "filename" },
  16631. { 0, "OSLBitmap", ufbxi_Filename },
  16632. { 0, "OSLBitmap2", ufbxi_Filename },
  16633. { 0, "UberBitmap", ufbxi_Filename },
  16634. { 0, "UberBitmap2", ufbxi_Filename },
  16635. };
  16636. ufbxi_noinline static void ufbxi_update_shader_texture(ufbx_texture *texture, ufbx_shader_texture *shader)
  16637. {
  16638. ufbxi_for_list(ufbx_shader_texture_input, input, shader->inputs) {
  16639. ufbx_prop *prop = input->prop;
  16640. if (prop) {
  16641. input->prop = prop = ufbx_find_prop_len(&texture->props, prop->name.data, prop->name.length);
  16642. input->value_vec4 = prop->value_vec4;
  16643. input->value_int = prop->value_int;
  16644. input->value_str = prop->value_str;
  16645. input->value_blob = prop->value_blob;
  16646. input->texture = (ufbx_texture*)ufbx_get_prop_element(&texture->element, input->prop, UFBX_ELEMENT_TEXTURE);
  16647. }
  16648. prop = input->texture_prop;
  16649. if (prop) {
  16650. input->texture_prop = prop = ufbx_find_prop_len(&texture->props, prop->name.data, prop->name.length);
  16651. ufbx_texture *tex = (ufbx_texture*)ufbx_get_prop_element(&texture->element, prop, UFBX_ELEMENT_TEXTURE);
  16652. if (tex) input->texture = tex;
  16653. }
  16654. input->texture_enabled = input->texture != NULL;
  16655. prop = input->texture_enabled_prop;
  16656. if (prop) {
  16657. input->texture_enabled_prop = prop = ufbx_find_prop_len(&texture->props, prop->name.data, prop->name.length);
  16658. input->texture_enabled = prop->value_int != 0;
  16659. }
  16660. }
  16661. if (shader->type == UFBX_SHADER_TEXTURE_SELECT_OUTPUT) {
  16662. ufbx_shader_texture_input *map = ufbx_find_shader_texture_input(shader, "sourceMap");
  16663. ufbx_shader_texture_input *index = ufbx_find_shader_texture_input(shader, "outputChannelIndex");
  16664. if (index) {
  16665. shader->main_texture_output_index = index->value_int;
  16666. }
  16667. if (map) {
  16668. shader->main_texture = map->texture;
  16669. map->texture_output_index = shader->main_texture_output_index;
  16670. }
  16671. }
  16672. }
  16673. ufbxi_nodiscard ufbxi_noinline static int ufbxi_finalize_shader_texture(ufbxi_context *uc, ufbx_texture *texture)
  16674. {
  16675. uint32_t classid_a = (uint32_t)(uint64_t)ufbx_find_int(&texture->props, "3dsMax|ClassIDa", 0);
  16676. uint32_t classid_b = (uint32_t)(uint64_t)ufbx_find_int(&texture->props, "3dsMax|ClassIDb", 0);
  16677. uint64_t classid = (uint64_t)classid_a << 32u | classid_b;
  16678. ufbx_string max_texture = ufbx_find_string(&texture->props, "3dsMax|MaxTexture", ufbx_empty_string);
  16679. // Check first if the texture looks like it could be a shader.
  16680. ufbx_shader_texture_type type = (ufbx_shader_texture_type)UFBX_SHADER_TEXTURE_TYPE_COUNT;
  16681. if (!strcmp(max_texture.data, "MULTIOUTPUT_TO_OSLMap") || classid == UINT64_C(0x896ef2fc44bd743f)) {
  16682. type = UFBX_SHADER_TEXTURE_SELECT_OUTPUT;
  16683. } else if (!strcmp(max_texture.data, "OSLMap") || classid == UINT64_C(0x7f9a7b9d6fcdf00d)) {
  16684. type = UFBX_SHADER_TEXTURE_OSL;
  16685. } else if (texture->type == UFBX_TEXTURE_FILE && texture->relative_filename.length == 0 && texture->absolute_filename.length == 0 && !texture->video) {
  16686. type = UFBX_SHADER_TEXTURE_UNKNOWN;
  16687. }
  16688. if ((uint32_t)type == UFBX_SHADER_TEXTURE_TYPE_COUNT) return 1;
  16689. ufbx_shader_texture *shader = ufbxi_push_zero(&uc->result, ufbx_shader_texture, 1);
  16690. ufbxi_check(shader);
  16691. shader->type = type;
  16692. static const char *const name_props[] = {
  16693. "3dsMax|params|OSLShaderName",
  16694. };
  16695. static const char *const source_props[] = {
  16696. "3dsMax|params|OSLCode",
  16697. };
  16698. shader->shader_source.data = ufbxi_empty_char;
  16699. shader->shader_name.data = ufbxi_empty_char;
  16700. ufbxi_nounroll for (size_t i = 0; i < ufbxi_arraycount(name_props); i++) {
  16701. ufbx_prop *prop = ufbx_find_prop(&texture->props, name_props[i]);
  16702. if (prop) {
  16703. shader->shader_name = prop->value_str;
  16704. break;
  16705. }
  16706. }
  16707. ufbxi_nounroll for (size_t i = 0; i < ufbxi_arraycount(source_props); i++) {
  16708. ufbx_prop *prop = ufbx_find_prop(&texture->props, source_props[i]);
  16709. if (prop) {
  16710. shader->shader_source = prop->value_str;
  16711. shader->raw_shader_source = prop->value_blob;
  16712. break;
  16713. }
  16714. }
  16715. ufbxi_check(ufbxi_shader_texture_find_prefix(uc, texture, shader));
  16716. if (shader->shader_name.length == 0) {
  16717. ufbx_string name = shader->prop_prefix;
  16718. if (ufbxi_remove_suffix_c(&name, " Parameters/Connections|")) {
  16719. size_t begin = name.length;
  16720. while (begin > 0 && name.data[begin - 1] != '|') {
  16721. begin--;
  16722. }
  16723. shader->shader_name.data = name.data + begin;
  16724. shader->shader_name.length = name.length - begin;
  16725. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, &shader->shader_name, false));
  16726. }
  16727. }
  16728. if (shader->shader_name.length == 0) {
  16729. if (max_texture.length > 0) {
  16730. shader->shader_name = max_texture;
  16731. }
  16732. }
  16733. if (classid != 0) {
  16734. shader->shader_type_id = classid;
  16735. }
  16736. if (shader->prop_prefix.length == 0) {
  16737. // If we not find any shader properties so we might have guessed wrong.
  16738. // We "leak" (freed with scene) the shader in this case but it's negligible.
  16739. return 1;
  16740. }
  16741. ufbxi_for_list(ufbx_prop, prop, texture->props.props) {
  16742. ufbx_string name = prop->name;
  16743. if (!ufbxi_remove_prefix_str(&name, shader->prop_prefix)) continue;
  16744. // Check if this property is a modifier to an existing input.
  16745. ufbx_string base_name = name;
  16746. if (ufbxi_remove_suffix_c(&base_name, "_map") || ufbxi_remove_suffix_c(&base_name, ".shader")) {
  16747. ufbx_shader_texture_input *base = ufbx_find_shader_texture_input_len(shader, base_name.data, base_name.length);
  16748. if (base) {
  16749. base->texture_prop = prop;
  16750. continue;
  16751. }
  16752. } else if (ufbxi_remove_suffix_c(&base_name, ".connected") || ufbxi_remove_suffix_c(&base_name, "Enabled")) {
  16753. ufbx_shader_texture_input *base = ufbx_find_shader_texture_input_len(shader, base_name.data, base_name.length);
  16754. if (base) {
  16755. base->texture_enabled_prop = prop;
  16756. continue;
  16757. }
  16758. }
  16759. // Use `uc->tmp_arr` to store the texture inputs so we can search them while we insert new ones.
  16760. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size,
  16761. (shader->inputs.count + 1) * sizeof(ufbx_shader_texture_input)));
  16762. shader->inputs.data = (ufbx_shader_texture_input*)uc->tmp_arr;
  16763. // Add a new property
  16764. ufbx_shader_texture_input *input = &shader->inputs.data[shader->inputs.count++];
  16765. memset(input, 0, sizeof(ufbx_shader_texture_input));
  16766. // NOTE: This is a bit hackish, we are using a suffix of an interned string. It won't compare
  16767. // pointer equal to the same string but that shouldn't matter..
  16768. input->name = name;
  16769. // Connect the property only, values and textures etc are fetched in `ufbxi_update_shader_texture()`.
  16770. input->prop = prop;
  16771. }
  16772. // Retain the shader inputs
  16773. shader->inputs.data = ufbxi_push_copy(&uc->result, ufbx_shader_texture_input, shader->inputs.count, shader->inputs.data);
  16774. ufbxi_check(shader->inputs.data);
  16775. texture->shader = shader;
  16776. texture->type = UFBX_TEXTURE_SHADER;
  16777. uc->scene.metadata.num_shader_textures++;
  16778. if (!uc->opts.disable_quirks) {
  16779. ufbxi_nounroll for (size_t i = 0; i < ufbxi_arraycount(ufbxi_file_shaders); i++) {
  16780. const ufbxi_file_shader *fs = &ufbxi_file_shaders[i];
  16781. if ((fs->shader_id && shader->shader_type_id == fs->shader_id) || !strcmp(shader->shader_name.data, fs->shader_name)) {
  16782. ufbx_shader_texture_input *input = ufbx_find_shader_texture_input(shader, fs->input_name);
  16783. if (input) {
  16784. // TODO: Support for specifying relative filename here if ever needed
  16785. ufbx_prop *prop = input->prop;
  16786. texture->absolute_filename = prop->value_str;
  16787. texture->raw_absolute_filename = prop->value_blob;
  16788. texture->type = UFBX_TEXTURE_FILE;
  16789. break;
  16790. }
  16791. }
  16792. }
  16793. }
  16794. ufbxi_update_shader_texture(texture, shader);
  16795. return 1;
  16796. }
  16797. ufbxi_noinline static void ufbxi_propagate_main_textures(ufbx_scene *scene)
  16798. {
  16799. // We need to do at least 2^(N-1) passes for N shader textures
  16800. size_t mask = scene->metadata.num_shader_textures;
  16801. while (mask) {
  16802. mask >>= 1;
  16803. ufbxi_for_ptr_list(ufbx_texture, p_texture, scene->textures) {
  16804. ufbx_texture *texture = *p_texture;
  16805. ufbx_shader_texture *shader = texture->shader;
  16806. if (!shader) continue;
  16807. ufbx_texture *main_tex = shader->main_texture;
  16808. if (!main_tex || shader->main_texture_output_index != 0) continue;
  16809. ufbx_shader_texture *main_shader = main_tex->shader;
  16810. if (!main_shader || !main_shader->main_texture) continue;
  16811. shader->main_texture = main_shader->main_texture;
  16812. shader->main_texture_output_index = main_shader->main_texture_output_index;
  16813. }
  16814. }
  16815. // Remove cyclic main textures
  16816. ufbxi_for_ptr_list(ufbx_texture, p_texture, scene->textures) {
  16817. ufbx_texture *texture = *p_texture;
  16818. ufbx_shader_texture *shader = texture->shader;
  16819. if (!shader || !shader->main_texture || shader->main_texture_output_index != 0) continue;
  16820. ufbx_texture *main_tex = shader->main_texture;
  16821. if (main_tex && main_tex->shader && main_tex->shader->main_texture) {
  16822. // Should have been propagated to `texture`
  16823. shader->main_texture = NULL;
  16824. }
  16825. }
  16826. ufbxi_for_ptr_list(ufbx_texture, p_texture, scene->textures) {
  16827. ufbx_texture *texture = *p_texture;
  16828. ufbx_shader_texture *shader = texture->shader;
  16829. if (!shader) continue;
  16830. ufbxi_for_list(ufbx_shader_texture_input, input, shader->inputs) {
  16831. if (!input->texture || !input->texture->shader) continue;
  16832. ufbx_shader_texture *input_shader = input->texture->shader;
  16833. if (input_shader->main_texture) {
  16834. input->texture = input_shader->main_texture;
  16835. input->texture_output_index = input_shader->main_texture_output_index;
  16836. }
  16837. }
  16838. }
  16839. ufbxi_for_ptr_list(ufbx_material, p_material, scene->materials) {
  16840. ufbx_material *material = *p_material;
  16841. ufbxi_for_list(ufbx_material_texture, tex, material->textures) {
  16842. ufbx_shader_texture *shader = tex->texture->shader;
  16843. if (shader && shader->main_texture && shader->main_texture_output_index == 0) {
  16844. tex->texture = shader->main_texture;
  16845. }
  16846. }
  16847. }
  16848. }
  16849. #define ufbxi_patch_empty(m_dst, m_len, m_src) \
  16850. do { if (!(m_dst).m_len) m_dst = m_src; } while (0)
  16851. ufbxi_nodiscard ufbxi_noinline static int ufbxi_insert_texture_file(ufbxi_context *uc, ufbx_texture *texture)
  16852. {
  16853. texture->file_index = UFBX_NO_INDEX;
  16854. const char *key = NULL;
  16855. // HACK: Even the raw entries have a null terminator so we can offset the
  16856. // pointer by one for relative filenames. This guarantees that an overlapping
  16857. // absolute and relative filenames will get separate textures.
  16858. if (texture->raw_absolute_filename.size > 0) {
  16859. key = (const char*)texture->raw_absolute_filename.data;
  16860. } else if (texture->raw_relative_filename.size > 0) {
  16861. key = (const char*)texture->raw_relative_filename.data + 1;
  16862. }
  16863. if (key == NULL) return 1;
  16864. uint32_t hash = ufbxi_hash_ptr(key);
  16865. ufbxi_texture_file_entry *entry = ufbxi_map_find(&uc->texture_file_map, ufbxi_texture_file_entry, hash, &key);
  16866. if (!entry) {
  16867. entry = ufbxi_map_insert(&uc->texture_file_map, ufbxi_texture_file_entry, hash, &key);
  16868. ufbxi_check(entry);
  16869. ufbx_texture_file *file = ufbxi_push_zero(&uc->tmp, ufbx_texture_file, 1);
  16870. ufbxi_check(file);
  16871. file->index = uc->texture_file_map.size - 1;
  16872. entry->key = key;
  16873. entry->file = file;
  16874. }
  16875. ufbx_texture_file *file = entry->file;
  16876. texture->file_index = file->index;
  16877. texture->has_file = true;
  16878. ufbxi_patch_empty(file->filename, length, texture->filename);
  16879. ufbxi_patch_empty(file->relative_filename, length, texture->relative_filename);
  16880. ufbxi_patch_empty(file->absolute_filename, length, texture->absolute_filename);
  16881. ufbxi_patch_empty(file->raw_filename, size, texture->raw_filename);
  16882. ufbxi_patch_empty(file->raw_relative_filename, size, texture->raw_relative_filename);
  16883. ufbxi_patch_empty(file->raw_absolute_filename, size, texture->raw_absolute_filename);
  16884. ufbxi_patch_empty(file->content, size, texture->content);
  16885. return 1;
  16886. }
  16887. ufbxi_nodiscard ufbxi_noinline static int ufbxi_pop_texture_files(ufbxi_context *uc)
  16888. {
  16889. uint32_t num_files = uc->texture_file_map.size;
  16890. ufbx_texture_file *files = ufbxi_push(&uc->result, ufbx_texture_file, num_files);
  16891. ufbxi_check(files);
  16892. uc->scene.texture_files.data = files;
  16893. uc->scene.texture_files.count = num_files;
  16894. ufbxi_texture_file_entry *entries = (ufbxi_texture_file_entry*)uc->texture_file_map.items;
  16895. for (size_t i = 0; i < num_files; i++) {
  16896. memcpy(&files[i], entries[i].file, sizeof(ufbx_texture_file));
  16897. }
  16898. return 1;
  16899. }
  16900. typedef struct {
  16901. ufbx_texture *texture;
  16902. size_t order;
  16903. } ufbxi_ordered_texture;
  16904. ufbxi_noinline static bool ufbxi_ordered_texture_less_texture(void *user, const void *va, const void *vb)
  16905. {
  16906. (void)user;
  16907. const ufbxi_ordered_texture *a = (const ufbxi_ordered_texture*)va, *b = (const ufbxi_ordered_texture*)vb;
  16908. return a->texture < b->texture;
  16909. }
  16910. ufbxi_noinline static bool ufbxi_ordered_texture_less_order(void *user, const void *va, const void *vb)
  16911. {
  16912. (void)user;
  16913. const ufbxi_ordered_texture *a = (const ufbxi_ordered_texture*)va, *b = (const ufbxi_ordered_texture*)vb;
  16914. return a->order < b->order;
  16915. }
  16916. ufbxi_nodiscard ufbxi_noinline static int ufbxi_deduplicate_textures(ufbxi_context *uc, ufbxi_buf *dst_buf, ufbxi_ordered_texture **p_dst, size_t *p_dst_count, size_t count)
  16917. {
  16918. ufbxi_ordered_texture *textures = ufbxi_push_pop(dst_buf, &uc->tmp_stack, ufbxi_ordered_texture, count);
  16919. ufbxi_check(textures);
  16920. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbxi_ordered_texture)));
  16921. ufbxi_stable_sort(sizeof(ufbxi_ordered_texture), 16, textures, uc->tmp_arr, count, &ufbxi_ordered_texture_less_texture, NULL);
  16922. // Remove adjacent duplicates
  16923. size_t dst_ix = 0;
  16924. for (size_t src_ix = 0; src_ix < count; src_ix++) {
  16925. if (src_ix > 0 && textures[src_ix - 1].texture == textures[src_ix].texture) {
  16926. continue;
  16927. } else {
  16928. if (src_ix != dst_ix) {
  16929. textures[dst_ix] = textures[src_ix];
  16930. }
  16931. dst_ix++;
  16932. }
  16933. }
  16934. size_t new_count = dst_ix;
  16935. ufbxi_stable_sort(sizeof(ufbxi_ordered_texture), 16, textures, uc->tmp_arr, new_count, &ufbxi_ordered_texture_less_order, NULL);
  16936. *p_dst_count = new_count;
  16937. *p_dst = textures;
  16938. return 1;
  16939. }
  16940. typedef enum {
  16941. UFBXI_FILE_TEXTURE_FETCH_INITIAL,
  16942. UFBXI_FILE_TEXTURE_FETCH_STARTED,
  16943. UFBXI_FILE_TEXTURE_FETCH_FINISHED,
  16944. } ufbxi_file_texture_fetch_state;
  16945. // Populate `ufbx_texture.file_textures[]` arrays.
  16946. ufbxi_nodiscard ufbxi_noinline static int ufbxi_fetch_file_textures(ufbxi_context *uc)
  16947. {
  16948. // We keep pointers to `ufbx_texture` in `tmp_stack` as a working set, since we don't know
  16949. // how deep the shader graphs might be.
  16950. // Start by pushing all the textures into the stack
  16951. size_t num_stack_textures = uc->scene.textures.count;
  16952. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_texture*, num_stack_textures, uc->scene.textures.data));
  16953. // Compressed `ufbxi_file_texture_fetch_state`
  16954. uint8_t *states = ufbxi_push_zero(&uc->tmp, uint8_t, uc->scene.textures.count);
  16955. ufbxi_check(states);
  16956. while (num_stack_textures-- > 0) {
  16957. ufbx_texture *texture = NULL;
  16958. ufbxi_pop(&uc->tmp_stack, ufbx_texture*, 1, &texture);
  16959. ufbxi_file_texture_fetch_state state = (ufbxi_file_texture_fetch_state)states[texture->typed_id];
  16960. if (state == UFBXI_FILE_TEXTURE_FETCH_FINISHED) continue;
  16961. ufbx_shader_texture *shader = texture->shader;
  16962. if (state == UFBXI_FILE_TEXTURE_FETCH_STARTED) {
  16963. states[texture->typed_id] = UFBXI_FILE_TEXTURE_FETCH_FINISHED;
  16964. // HACK: Reuse `tmp_parse` for storing intermediate information as we can clear it.
  16965. ufbxi_buf_clear(&uc->tmp_parse);
  16966. // Now all non-cyclical dependents should be processed.
  16967. size_t num_deps = 0;
  16968. if (texture->type == UFBX_TEXTURE_FILE) {
  16969. ufbxi_ordered_texture *dst = ufbxi_push(&uc->tmp_stack, ufbxi_ordered_texture, 1);
  16970. ufbxi_check(dst);
  16971. dst->texture = texture;
  16972. dst->order = num_deps++;
  16973. }
  16974. ufbxi_for_list(ufbx_texture_layer, layer, texture->layers) {
  16975. ufbx_texture *dep_tex = layer->texture;
  16976. if (dep_tex->file_textures.count > 0) {
  16977. ufbxi_ordered_texture *dst = ufbxi_push(&uc->tmp_stack, ufbxi_ordered_texture, 1);
  16978. ufbxi_check(dst);
  16979. dst->texture = dep_tex;
  16980. dst->order = num_deps++;
  16981. }
  16982. }
  16983. if (shader) {
  16984. ufbxi_for_list(ufbx_shader_texture_input, input, shader->inputs) {
  16985. ufbx_texture *dep_tex = input->texture;
  16986. if (dep_tex && dep_tex->file_textures.count > 0) {
  16987. ufbxi_ordered_texture *dst = ufbxi_push(&uc->tmp_stack, ufbxi_ordered_texture, 1);
  16988. ufbxi_check(dst);
  16989. dst->texture = dep_tex;
  16990. dst->order = num_deps++;
  16991. }
  16992. }
  16993. }
  16994. // Deduplicate the direct dependencies first
  16995. ufbxi_ordered_texture *deps;
  16996. ufbxi_check(ufbxi_deduplicate_textures(uc, &uc->tmp_parse, &deps, &num_deps, num_deps));
  16997. if (num_deps == 1) {
  16998. // If we have only a single dependency (that is not the same one) we can just copy the pointer
  16999. texture->file_textures = deps[0].texture->file_textures;
  17000. } else {
  17001. // Now collect all the file textures and deduplicate them
  17002. size_t num_files = 0;
  17003. ufbxi_for(ufbxi_ordered_texture, dep, deps, num_deps) {
  17004. ufbxi_for_ptr_list(ufbx_texture, p_tex, dep->texture->file_textures) {
  17005. ufbxi_ordered_texture *dst = ufbxi_push(&uc->tmp_stack, ufbxi_ordered_texture, 1);
  17006. ufbxi_check(dst);
  17007. dst->texture = *p_tex;
  17008. dst->order = num_files++;
  17009. }
  17010. }
  17011. // Deduplicate the file textures
  17012. ufbxi_ordered_texture *files;
  17013. ufbxi_check(ufbxi_deduplicate_textures(uc, &uc->tmp_parse, &files, &num_files, num_files));
  17014. texture->file_textures.count = num_files;
  17015. texture->file_textures.data = ufbxi_push(&uc->result, ufbx_texture*, num_files);
  17016. ufbxi_check(texture->file_textures.data);
  17017. for (size_t i = 0; i < num_files; i++) {
  17018. texture->file_textures.data[i] = files[i].texture;
  17019. }
  17020. }
  17021. } else {
  17022. if (texture->type == UFBX_TEXTURE_FILE) {
  17023. // Simple case: Just point to self
  17024. texture->file_textures.count = 1;
  17025. texture->file_textures.data = ufbxi_push(&uc->result, ufbx_texture*, 1);
  17026. ufbxi_check(texture->file_textures.data);
  17027. texture->file_textures.data[0] = texture;
  17028. // In simple cases we can quit here, for more complex file textures queue
  17029. // the texture in case there are other file textures as inputs.
  17030. if (!texture->shader) {
  17031. states[texture->typed_id] = UFBXI_FILE_TEXTURE_FETCH_FINISHED;
  17032. continue;
  17033. }
  17034. }
  17035. // Complex: Process all dependencies first
  17036. states[texture->typed_id] = UFBXI_FILE_TEXTURE_FETCH_STARTED;
  17037. // Push self first so we can return after processing dependencies
  17038. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_texture*, 1, &texture));
  17039. num_stack_textures++;
  17040. ufbxi_for_list(ufbx_texture_layer, layer, texture->layers) {
  17041. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_texture*, 1, &layer->texture));
  17042. num_stack_textures++;
  17043. }
  17044. if (shader) {
  17045. ufbxi_for_list(ufbx_shader_texture_input, input, shader->inputs) {
  17046. if (input->texture) {
  17047. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_texture*, 1, &input->texture));
  17048. num_stack_textures++;
  17049. }
  17050. }
  17051. }
  17052. }
  17053. }
  17054. return 1;
  17055. }
  17056. ufbxi_nodiscard ufbxi_noinline static ufbx_node *ufbxi_get_geometry_transform_node(ufbx_element *element)
  17057. {
  17058. if (element->instances.count == 1) {
  17059. ufbx_node *node = element->instances.data[0];
  17060. if (node->has_geometry_transform) return node;
  17061. }
  17062. return NULL;
  17063. }
  17064. ufbxi_noinline static void ufbxi_mirror_vec3_list(const void *v_list, ufbx_mirror_axis axis, size_t stride)
  17065. {
  17066. const ufbx_void_list *list = (const ufbx_void_list*)v_list;
  17067. if (axis == UFBX_MIRROR_AXIS_NONE || !list || list->count == 0) return;
  17068. if (!stride) stride = sizeof(ufbx_vec3);
  17069. void *ptr = (char*)list->data + (size_t)((int)axis - 1) * sizeof(ufbx_real);
  17070. void *end = (char*)ptr + list->count * stride;
  17071. while (ptr != end) {
  17072. ufbx_real *v = (ufbx_real*)ptr;
  17073. *v = -*v;
  17074. ptr = (char*)ptr + stride;
  17075. }
  17076. }
  17077. ufbxi_noinline static void ufbxi_scale_vec3_list(const void *v_list, ufbx_real scale, size_t stride)
  17078. {
  17079. const ufbx_void_list *list = (const ufbx_void_list*)v_list;
  17080. if (!list || list->count == 0) return;
  17081. if (!stride) stride = sizeof(ufbx_vec3);
  17082. void *ptr = list->data, *end = (char*)ptr + list->count * stride;
  17083. while (ptr != end) {
  17084. ufbx_vec3 *v = (ufbx_vec3*)ptr;
  17085. v->x *= scale;
  17086. v->y *= scale;
  17087. v->z *= scale;
  17088. ptr = (char*)ptr + stride;
  17089. }
  17090. }
  17091. ufbxi_noinline static void ufbxi_transform_vec3_list(const void *v_list, const ufbx_matrix *matrix, size_t stride)
  17092. {
  17093. const ufbx_void_list *list = (const ufbx_void_list*)v_list;
  17094. if (!list || list->count == 0) return;
  17095. if (!stride) stride = sizeof(ufbx_vec3);
  17096. void *ptr = list->data, *end = (char*)ptr + list->count * stride;
  17097. while (ptr != end) {
  17098. ufbx_vec3 *v = (ufbx_vec3*)ptr;
  17099. *v = ufbx_transform_position(matrix, *v);
  17100. ptr = (char*)ptr + stride;
  17101. }
  17102. }
  17103. ufbxi_noinline static void ufbxi_normalize_vec3_list(const ufbx_vec3_list *list)
  17104. {
  17105. ufbxi_nounroll ufbxi_for_list(ufbx_vec3, normal, *list) {
  17106. *normal = ufbxi_normalize3(*normal);
  17107. }
  17108. }
  17109. // Forward declare as we're kind of preprocessing ata here that would usually happen later.
  17110. ufbxi_noinline static ufbx_transform ufbxi_get_geometry_transform(const ufbx_props *props, ufbx_node *node);
  17111. ufbxi_nodiscard ufbxi_noinline static int ufbxi_flip_attrib_winding(ufbxi_context *uc, ufbx_mesh *mesh, ufbx_uint32_list *indices, bool is_position)
  17112. {
  17113. // All zero, no flipping needed
  17114. if (indices->data == uc->zero_indices || indices->count == 0) return 1;
  17115. if (indices->data == mesh->vertex_position.indices.data && !is_position) {
  17116. // Sharing indices with vertex position, already flipped.
  17117. return 1;
  17118. } else if (indices->data == uc->consecutive_indices) {
  17119. // Need to duplicate consecutive indices, but we can cache the per mesh.
  17120. if (uc->tmp_mesh_consecutive_indices) {
  17121. indices->data = uc->tmp_mesh_consecutive_indices;
  17122. return 1;
  17123. }
  17124. indices->data = ufbxi_push_copy(&uc->result, uint32_t, indices->count, indices->data);
  17125. ufbxi_check(indices->data);
  17126. uc->tmp_mesh_consecutive_indices = indices->data;
  17127. }
  17128. uint32_t *data = indices->data;
  17129. ufbxi_for_list(ufbx_face, face, mesh->faces) {
  17130. if (face->num_indices == 0) continue;
  17131. size_t begin = face->index_begin + 1;
  17132. size_t end = face->index_begin + face->num_indices - 1;
  17133. while (begin < end) {
  17134. uint32_t tmp = data[begin];
  17135. data[begin] = data[end];
  17136. data[end] = tmp;
  17137. begin++;
  17138. end--;
  17139. }
  17140. }
  17141. return 1;
  17142. }
  17143. ufbxi_nodiscard ufbxi_noinline static int ufbxi_flip_winding(ufbxi_context *uc, ufbx_mesh *mesh)
  17144. {
  17145. uc->tmp_mesh_consecutive_indices = NULL;
  17146. ufbxi_check(ufbxi_flip_attrib_winding(uc, mesh, &mesh->vertex_position.indices, true));
  17147. ufbxi_check(ufbxi_flip_attrib_winding(uc, mesh, &mesh->vertex_normal.indices, false));
  17148. ufbxi_check(ufbxi_flip_attrib_winding(uc, mesh, &mesh->vertex_crease.indices, false));
  17149. if (mesh->uv_sets.count > 0) {
  17150. ufbxi_for_list(ufbx_uv_set, set, mesh->uv_sets) {
  17151. ufbxi_check(ufbxi_flip_attrib_winding(uc, mesh, &set->vertex_uv.indices, false));
  17152. ufbxi_check(ufbxi_flip_attrib_winding(uc, mesh, &set->vertex_tangent.indices, false));
  17153. ufbxi_check(ufbxi_flip_attrib_winding(uc, mesh, &set->vertex_bitangent.indices, false));
  17154. }
  17155. mesh->vertex_uv = mesh->uv_sets.data[0].vertex_uv;
  17156. mesh->vertex_bitangent = mesh->uv_sets.data[0].vertex_bitangent;
  17157. mesh->vertex_tangent = mesh->uv_sets.data[0].vertex_tangent;
  17158. }
  17159. if (mesh->color_sets.count > 0) {
  17160. ufbxi_for_list(ufbx_color_set, set, mesh->color_sets) {
  17161. ufbxi_check(ufbxi_flip_attrib_winding(uc, mesh, &set->vertex_color.indices, false));
  17162. }
  17163. mesh->vertex_color = mesh->color_sets.data[0].vertex_color;
  17164. }
  17165. ufbxi_check(ufbxi_flip_attrib_winding(uc, mesh, &mesh->skinned_position.indices, false));
  17166. if (mesh->skinned_normal.indices.data != mesh->vertex_normal.indices.data) {
  17167. ufbxi_check(ufbxi_flip_attrib_winding(uc, mesh, &mesh->skinned_normal.indices, false));
  17168. }
  17169. ufbxi_update_vertex_first_index(mesh);
  17170. // Mapping from old index values to flipped ones, reserve index -1
  17171. // (aka `UFBX_NO_INDEX`) for itself.
  17172. if (mesh->edges.count > 0) {
  17173. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, (mesh->num_indices + 1) * sizeof(uint32_t)));
  17174. uint32_t *index_mapping = (uint32_t*)uc->tmp_arr + 1;
  17175. index_mapping[-1] = UFBX_NO_INDEX;
  17176. ufbxi_for_list(ufbx_face, face, mesh->faces) {
  17177. if (face->num_indices == 0) continue;
  17178. uint32_t begin = face->index_begin;
  17179. uint32_t count = face->num_indices - 1;
  17180. index_mapping[begin] = begin;
  17181. for (uint32_t i = 0; i < count; i++) {
  17182. index_mapping[begin + 1 + i] = begin + count - i;
  17183. }
  17184. }
  17185. ufbxi_for_list(ufbx_edge, p_edge, mesh->edges) {
  17186. uint32_t a = index_mapping[(int32_t)p_edge->a];
  17187. uint32_t b = index_mapping[(int32_t)p_edge->b];
  17188. p_edge->a = b;
  17189. p_edge->b = a;
  17190. }
  17191. }
  17192. return 1;
  17193. }
  17194. ufbxi_nodiscard ufbxi_noinline static int ufbxi_modify_geometry(ufbxi_context *uc)
  17195. {
  17196. bool do_mirror = false;
  17197. bool do_winding = uc->opts.reverse_winding;
  17198. bool do_scale = false;
  17199. bool do_geometry_transforms = false;
  17200. if (uc->opts.geometry_transform_handling == UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY
  17201. || uc->opts.geometry_transform_handling == UFBX_GEOMETRY_TRANSFORM_HANDLING_MODIFY_GEOMETRY_NO_FALLBACK) {
  17202. // Prefetch geometry transforms for processing, they will later be overwritten in `ufbxi_update_node()`.
  17203. ufbxi_for_ptr_list(ufbx_node, p_node, uc->scene.nodes) {
  17204. ufbx_node *node = *p_node;
  17205. if (node->is_root) continue;
  17206. node->geometry_transform = ufbxi_get_geometry_transform(&node->props, node);
  17207. if (!ufbxi_is_transform_identity(&node->geometry_transform)) {
  17208. node->geometry_to_node = ufbx_transform_to_matrix(&node->geometry_transform);
  17209. node->has_geometry_transform = true;
  17210. } else {
  17211. node->geometry_to_node = ufbx_identity_matrix;
  17212. node->has_geometry_transform = false;
  17213. }
  17214. }
  17215. do_geometry_transforms = true;
  17216. }
  17217. if (uc->mirror_axis != 0) {
  17218. do_mirror = true;
  17219. }
  17220. if (uc->scene.metadata.geometry_scale != 1.0f) {
  17221. do_scale = true;
  17222. }
  17223. ufbx_real geometry_scale = uc->scene.metadata.geometry_scale;
  17224. ufbx_mirror_axis mirror_axis = uc->mirror_axis;
  17225. ufbxi_for_ptr_list(ufbx_blend_shape, p_shape, uc->scene.blend_shapes) {
  17226. ufbx_blend_shape *shape = *p_shape;
  17227. if (do_scale) {
  17228. ufbxi_scale_vec3_list(&shape->position_offsets, geometry_scale, 0);
  17229. }
  17230. if (do_mirror) {
  17231. ufbxi_mirror_vec3_list(&shape->position_offsets, mirror_axis, 0);
  17232. ufbxi_mirror_vec3_list(&shape->normal_offsets, mirror_axis, 0);
  17233. }
  17234. }
  17235. ufbxi_for_ptr_list(ufbx_mesh, p_mesh, uc->scene.meshes) {
  17236. ufbx_mesh *mesh = *p_mesh;
  17237. if (do_scale) {
  17238. ufbxi_scale_vec3_list(&mesh->vertex_position.values, geometry_scale, 0);
  17239. }
  17240. bool do_flip_winding = do_winding;
  17241. if (do_mirror) {
  17242. ufbxi_mirror_vec3_list(&mesh->vertex_position.values, mirror_axis, 0);
  17243. ufbxi_mirror_vec3_list(&mesh->vertex_normal.values, mirror_axis, 0);
  17244. ufbxi_for_list(ufbx_uv_set, set, mesh->uv_sets) {
  17245. ufbxi_mirror_vec3_list(&set->vertex_tangent.values, mirror_axis, 0);
  17246. ufbxi_mirror_vec3_list(&set->vertex_bitangent.values, mirror_axis, 0);
  17247. }
  17248. if (!uc->opts.handedness_conversion_retain_winding) {
  17249. do_flip_winding = !do_flip_winding;
  17250. }
  17251. }
  17252. // Flip face winding retaining the first vertex
  17253. if (do_flip_winding) {
  17254. mesh->reversed_winding = true;
  17255. ufbxi_check(ufbxi_flip_winding(uc, mesh));
  17256. }
  17257. ufbx_node *geo_node = ufbxi_get_geometry_transform_node(&mesh->element);
  17258. if (do_geometry_transforms && geo_node) {
  17259. ufbx_matrix tangent_matrix = geo_node->geometry_to_node;
  17260. tangent_matrix.m03 = 0.0f;
  17261. tangent_matrix.m13 = 0.0f;
  17262. tangent_matrix.m23 = 0.0f;
  17263. ufbx_matrix normal_matrix = ufbx_matrix_for_normals(&geo_node->geometry_to_node);
  17264. ufbxi_transform_vec3_list(&mesh->vertex_position.values, &geo_node->geometry_to_node, 0);
  17265. ufbxi_transform_vec3_list(&mesh->vertex_normal.values, &normal_matrix, 0);
  17266. ufbxi_normalize_vec3_list(&mesh->vertex_normal.values);
  17267. ufbxi_for_list(ufbx_uv_set, set, mesh->uv_sets) {
  17268. ufbxi_transform_vec3_list(&set->vertex_tangent.values, &tangent_matrix, 0);
  17269. ufbxi_transform_vec3_list(&set->vertex_bitangent.values, &tangent_matrix, 0);
  17270. ufbxi_normalize_vec3_list(&set->vertex_tangent.values);
  17271. ufbxi_normalize_vec3_list(&set->vertex_bitangent.values);
  17272. }
  17273. }
  17274. }
  17275. ufbxi_for_ptr_list(ufbx_line_curve, p_curve, uc->scene.line_curves) {
  17276. ufbx_line_curve *curve = *p_curve;
  17277. if (do_scale) {
  17278. ufbxi_scale_vec3_list(&curve->control_points, geometry_scale, 0);
  17279. }
  17280. if (do_mirror) {
  17281. ufbxi_mirror_vec3_list(&curve->control_points, mirror_axis, 0);
  17282. }
  17283. ufbx_node *geo_node = ufbxi_get_geometry_transform_node(&curve->element);
  17284. if (do_geometry_transforms && geo_node) {
  17285. ufbxi_transform_vec3_list(&curve->control_points, &geo_node->geometry_to_node, 0);
  17286. }
  17287. }
  17288. ufbxi_for_ptr_list(ufbx_nurbs_curve, p_curve, uc->scene.nurbs_curves) {
  17289. ufbx_nurbs_curve *curve = *p_curve;
  17290. if (do_scale) {
  17291. ufbxi_scale_vec3_list(&curve->control_points, geometry_scale, sizeof(ufbx_vec4));
  17292. }
  17293. if (do_mirror) {
  17294. ufbxi_mirror_vec3_list(&curve->control_points, mirror_axis, sizeof(ufbx_vec4));
  17295. }
  17296. ufbx_node *geo_node = ufbxi_get_geometry_transform_node(&curve->element);
  17297. if (do_geometry_transforms && geo_node) {
  17298. ufbxi_transform_vec3_list(&curve->control_points, &geo_node->geometry_to_node, sizeof(ufbx_vec4));
  17299. }
  17300. }
  17301. ufbxi_for_ptr_list(ufbx_nurbs_surface, p_surface, uc->scene.nurbs_surfaces) {
  17302. ufbx_nurbs_surface *surface = *p_surface;
  17303. if (do_scale) {
  17304. ufbxi_scale_vec3_list(&surface->control_points, geometry_scale, sizeof(ufbx_vec4));
  17305. }
  17306. if (do_mirror) {
  17307. ufbxi_mirror_vec3_list(&surface->control_points, mirror_axis, sizeof(ufbx_vec4));
  17308. }
  17309. ufbx_node *geo_node = ufbxi_get_geometry_transform_node(&surface->element);
  17310. if (do_geometry_transforms && geo_node) {
  17311. ufbxi_transform_vec3_list(&surface->control_points, &geo_node->geometry_to_node, sizeof(ufbx_vec4));
  17312. }
  17313. }
  17314. if (uc->opts.geometry_transform_handling != UFBX_GEOMETRY_TRANSFORM_HANDLING_PRESERVE) {
  17315. // Reset all geometry transforms if we're not preserving them
  17316. ufbx_props *defaults = NULL;
  17317. ufbxi_for_ptr_list(ufbx_node, p_node, uc->scene.nodes) {
  17318. ufbx_node *node = *p_node;
  17319. if (!defaults) defaults = node->props.defaults;
  17320. if (node->has_geometry_transform) {
  17321. ufbxi_set_own_prop_vec3_uniform(&node->props, ufbxi_GeometricTranslation, 0.0f);
  17322. ufbxi_set_own_prop_vec3_uniform(&node->props, ufbxi_GeometricRotation, 0.0f);
  17323. ufbxi_set_own_prop_vec3_uniform(&node->props, ufbxi_GeometricScaling, 1.0f);
  17324. }
  17325. }
  17326. if (defaults) {
  17327. ufbxi_set_own_prop_vec3_uniform(defaults, ufbxi_GeometricTranslation, 0.0f);
  17328. ufbxi_set_own_prop_vec3_uniform(defaults, ufbxi_GeometricRotation, 0.0f);
  17329. ufbxi_set_own_prop_vec3_uniform(defaults, ufbxi_GeometricScaling, 1.0f);
  17330. }
  17331. }
  17332. return 1;
  17333. }
  17334. ufbxi_noinline static void ufbxi_postprocess_scene(ufbxi_context *uc)
  17335. {
  17336. if (uc->opts.normalize_normals || uc->opts.normalize_tangents) {
  17337. ufbxi_for_ptr_list(ufbx_mesh, p_mesh, uc->scene.meshes) {
  17338. ufbx_mesh *mesh = *p_mesh;
  17339. if (uc->opts.normalize_normals) {
  17340. ufbxi_normalize_vec3_list(&mesh->vertex_normal.values);
  17341. }
  17342. if (uc->opts.normalize_tangents) {
  17343. ufbxi_for_list(ufbx_uv_set, set, mesh->uv_sets) {
  17344. ufbxi_normalize_vec3_list(&mesh->vertex_tangent.values);
  17345. ufbxi_normalize_vec3_list(&mesh->vertex_bitangent.values);
  17346. }
  17347. }
  17348. }
  17349. }
  17350. if (uc->exporter == UFBX_EXPORTER_BLENDER_BINARY) {
  17351. uc->scene.metadata.ortho_size_unit = 1.0f / uc->scene.metadata.geometry_scale;
  17352. } else {
  17353. uc->scene.metadata.ortho_size_unit = 30.0f;
  17354. }
  17355. }
  17356. ufbxi_noinline static size_t ufbxi_next_path_segment(const char *data, size_t begin, size_t length)
  17357. {
  17358. for (size_t i = begin; i < length; i++) {
  17359. if (data[i] == '/' || data[i] == '\\') {
  17360. return i;
  17361. }
  17362. }
  17363. return length;
  17364. }
  17365. ufbxi_nodiscard ufbxi_noinline static int ufbxi_absolute_to_relative_path(ufbxi_context *uc, ufbxi_strblob *p_dst, const ufbxi_strblob *p_rel, const ufbxi_strblob *p_src, bool raw)
  17366. {
  17367. const char *rel = ufbxi_strblob_data(p_rel, raw);
  17368. const char *src = ufbxi_strblob_data(p_src, raw);
  17369. size_t rel_length = ufbxi_strblob_length(p_rel, raw);
  17370. size_t src_length = ufbxi_strblob_length(p_src, raw);
  17371. if (rel_length == 0 || src_length == 0) return 1;
  17372. // Absolute paths must start with the same character (either drive or '/')
  17373. if (rel[0] != src[0]) return 1;
  17374. // Find the last directory of the path we want to be relative to
  17375. while (rel_length > 0 && (rel[rel_length - 1] != '/' && rel[rel_length - 1] != '\\')) {
  17376. rel_length--;
  17377. }
  17378. if (rel_length == 0) return 1;
  17379. char separator = rel[rel_length - 1];
  17380. size_t max_length = rel_length * 2 + src_length;
  17381. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, max_length));
  17382. char *tmp = uc->tmp_arr;
  17383. size_t tmp_length = 0;
  17384. size_t rel_begin = 0;
  17385. size_t src_begin = 0;
  17386. while (rel_begin < rel_length && src_begin < src_length) {
  17387. size_t rel_end = ufbxi_next_path_segment(rel, rel_begin, rel_length);
  17388. size_t src_end = ufbxi_next_path_segment(src, src_begin, src_length);
  17389. if (rel_end != src_end || memcmp(rel + rel_begin, src + src_begin, src_end - src_begin) != 0) break;
  17390. rel_begin = rel_end + 1;
  17391. src_begin = src_end + 1;
  17392. }
  17393. while (rel_begin < rel_length) {
  17394. size_t rel_end = ufbxi_next_path_segment(rel, rel_begin, rel_length);
  17395. tmp[tmp_length++] = '.';
  17396. tmp[tmp_length++] = '.';
  17397. tmp[tmp_length++] = separator;
  17398. rel_begin = rel_end + 1;
  17399. }
  17400. while (src_begin < src_length) {
  17401. size_t src_end = ufbxi_next_path_segment(src, src_begin, src_length);
  17402. size_t len = src_end - src_begin;
  17403. memcpy(tmp + tmp_length, src + src_begin, len);
  17404. tmp_length += len;
  17405. if (src_end < src_length) {
  17406. tmp[tmp_length++] = separator;
  17407. }
  17408. src_begin = src_end + 1;
  17409. }
  17410. ufbx_assert(tmp_length <= max_length);
  17411. const char *dst = ufbxi_push_string(&uc->string_pool, tmp, tmp_length, NULL, true);
  17412. ufbxi_check(dst);
  17413. ufbxi_strblob_set(p_dst, dst, tmp_length, raw);
  17414. return 1;
  17415. }
  17416. ufbxi_nodiscard ufbxi_noinline static int ufbxi_resolve_filenames(ufbxi_context *uc, ufbxi_strblob *filename, ufbxi_strblob *absolute_filename, ufbxi_strblob *relative_filename, bool raw)
  17417. {
  17418. if (ufbxi_strblob_length(relative_filename, raw) == 0) {
  17419. const ufbxi_strblob *original_file_path = raw
  17420. ? (const ufbxi_strblob*)&uc->scene.metadata.raw_original_file_path
  17421. : (const ufbxi_strblob*)&uc->scene.metadata.original_file_path;
  17422. ufbxi_check(ufbxi_absolute_to_relative_path(uc, relative_filename, original_file_path, absolute_filename, raw));
  17423. }
  17424. ufbxi_check(ufbxi_resolve_relative_filename(uc, filename, relative_filename, raw));
  17425. return 1;
  17426. }
  17427. ufbxi_noinline static bool ufbxi_file_content_less(void *user, const void *va, const void *vb)
  17428. {
  17429. (void)user;
  17430. const ufbxi_file_content *a = (const ufbxi_file_content*)va, *b = (const ufbxi_file_content*)vb;
  17431. return ufbxi_str_less(a->absolute_filename, b->absolute_filename);
  17432. }
  17433. ufbxi_nodiscard ufbxi_noinline static int ufbxi_sort_file_contents(ufbxi_context *uc, ufbxi_file_content *content, size_t count)
  17434. {
  17435. ufbxi_check(ufbxi_grow_array(&uc->ator_tmp, &uc->tmp_arr, &uc->tmp_arr_size, count * sizeof(ufbxi_file_content)));
  17436. ufbxi_stable_sort(sizeof(ufbxi_file_content), 32, content, uc->tmp_arr, count, &ufbxi_file_content_less, NULL);
  17437. return 1;
  17438. }
  17439. ufbxi_nodiscard ufbxi_noinline static int ufbxi_push_file_content(ufbxi_context *uc, ufbx_string *p_filename, ufbx_blob *p_data)
  17440. {
  17441. if (p_data->size == 0 || p_filename->length == 0) return 1;
  17442. ufbxi_file_content *content = ufbxi_push(&uc->tmp_stack, ufbxi_file_content, 1);
  17443. ufbxi_check(content);
  17444. content->absolute_filename = *p_filename;
  17445. content->content = *p_data;
  17446. return 1;
  17447. }
  17448. ufbxi_noinline static void ufbxi_fetch_file_content(ufbxi_context *uc, ufbx_string *p_filename, ufbx_blob *p_data)
  17449. {
  17450. if (p_data->size > 0) return;
  17451. ufbx_string filename = *p_filename;
  17452. size_t index = SIZE_MAX;
  17453. ufbxi_macro_lower_bound_eq(ufbxi_file_content, 8, &index, uc->file_content, 0, uc->num_file_content,
  17454. ( ufbxi_str_less(a->absolute_filename, filename) ),
  17455. ( a->absolute_filename.data == filename.data ));
  17456. if (index != SIZE_MAX) {
  17457. *p_data = uc->file_content[index].content;
  17458. }
  17459. }
  17460. ufbxi_nodiscard ufbxi_noinline static int ufbxi_resolve_file_content(ufbxi_context *uc)
  17461. {
  17462. size_t initial_stack = uc->tmp_stack.num_items;
  17463. ufbxi_for_ptr_list(ufbx_video, p_video, uc->scene.videos) {
  17464. ufbx_video *video = *p_video;
  17465. ufbxi_check(ufbxi_resolve_filenames(uc, (ufbxi_strblob*)&video->filename, (ufbxi_strblob*)&video->absolute_filename, (ufbxi_strblob*)&video->relative_filename, false));
  17466. ufbxi_check(ufbxi_resolve_filenames(uc, (ufbxi_strblob*)&video->raw_filename, (ufbxi_strblob*)&video->raw_absolute_filename, (ufbxi_strblob*)&video->raw_relative_filename, true));
  17467. ufbxi_check(ufbxi_push_file_content(uc, &video->absolute_filename, &video->content));
  17468. }
  17469. ufbxi_for_ptr_list(ufbx_audio_clip, p_clip, uc->scene.audio_clips) {
  17470. ufbx_audio_clip *clip = *p_clip;
  17471. clip->absolute_filename = ufbx_find_string(&clip->props, "Path", ufbx_empty_string);
  17472. clip->relative_filename = ufbx_find_string(&clip->props, "RelPath", ufbx_empty_string);
  17473. clip->raw_absolute_filename = ufbx_find_blob(&clip->props, "Path", ufbx_empty_blob);
  17474. clip->raw_relative_filename = ufbx_find_blob(&clip->props, "RelPath", ufbx_empty_blob);
  17475. ufbxi_check(ufbxi_resolve_filenames(uc, (ufbxi_strblob*)&clip->filename, (ufbxi_strblob*)&clip->absolute_filename, (ufbxi_strblob*)&clip->relative_filename, false));
  17476. ufbxi_check(ufbxi_resolve_filenames(uc, (ufbxi_strblob*)&clip->raw_filename, (ufbxi_strblob*)&clip->raw_absolute_filename, (ufbxi_strblob*)&clip->raw_relative_filename, true));
  17477. ufbxi_check(ufbxi_push_file_content(uc, &clip->absolute_filename, &clip->content));
  17478. }
  17479. uc->num_file_content = uc->tmp_stack.num_items - initial_stack;
  17480. uc->file_content = ufbxi_push_pop(&uc->tmp, &uc->tmp_stack, ufbxi_file_content, uc->num_file_content);
  17481. ufbxi_check(uc->file_content);
  17482. ufbxi_check(ufbxi_sort_file_contents(uc, uc->file_content, uc->num_file_content));
  17483. ufbxi_for_ptr_list(ufbx_video, p_video, uc->scene.videos) {
  17484. ufbx_video *video = *p_video;
  17485. ufbxi_fetch_file_content(uc, &video->absolute_filename, &video->content);
  17486. }
  17487. ufbxi_for_ptr_list(ufbx_audio_clip, p_clip, uc->scene.audio_clips) {
  17488. ufbx_audio_clip *clip = *p_clip;
  17489. ufbxi_fetch_file_content(uc, &clip->absolute_filename, &clip->content);
  17490. }
  17491. return 1;
  17492. }
  17493. ufbxi_nodiscard ufbxi_noinline static int ufbxi_validate_indices(ufbxi_context *uc, ufbx_uint32_list *indices, size_t max_index)
  17494. {
  17495. if (max_index == 0 && uc->opts.index_error_handling == UFBX_INDEX_ERROR_HANDLING_CLAMP) {
  17496. indices->data = NULL;
  17497. indices->count = 0;
  17498. return 1;
  17499. }
  17500. ufbxi_nounroll ufbxi_for_list(uint32_t, p_ix, *indices) {
  17501. uint32_t ix = *p_ix;
  17502. if (ix >= max_index) {
  17503. ufbxi_check(ufbxi_fix_index(uc, p_ix, ix, max_index));
  17504. }
  17505. }
  17506. return 1;
  17507. }
  17508. static bool ufbxi_material_part_usage_less(void *user, const void *va, const void *vb)
  17509. {
  17510. ufbx_mesh_part *parts = (ufbx_mesh_part*)user;
  17511. uint32_t a = *(const uint32_t*)va, b = *(const uint32_t*)vb;
  17512. ufbx_mesh_part *pa = &parts[a];
  17513. ufbx_mesh_part *pb = &parts[b];
  17514. if (pa->face_indices.count == 0 || pb->face_indices.count == 0) {
  17515. if (pa->face_indices.count == pb->face_indices.count) return a < b;
  17516. return pa->face_indices.count > pb->face_indices.count;
  17517. }
  17518. return pa->face_indices.data[0] < pb->face_indices.data[0];
  17519. }
  17520. ufbxi_nodiscard static ufbxi_noinline int ufbxi_finalize_mesh_material(ufbxi_buf *buf, ufbx_error *error, ufbx_mesh *mesh)
  17521. {
  17522. size_t num_materials = mesh->materials.count;
  17523. size_t num_parts = mesh->material_parts.count;
  17524. size_t num_faces = mesh->faces.count;
  17525. ufbx_mesh_part *parts = mesh->material_parts.data;
  17526. ufbx_assert(!parts || (mesh->material_parts.count == num_materials) || (mesh->material_parts.count == 1 && num_materials == 0));
  17527. uint32_t *face_material = mesh->face_material.data;
  17528. // Count the number of faces and triangles per material
  17529. ufbxi_nounroll for (size_t i = 0; i < num_faces; i++) {
  17530. ufbx_face face = mesh->faces.data[i];
  17531. uint32_t mat_ix = 0;
  17532. if (face_material) {
  17533. mat_ix = face_material[i];
  17534. if (mat_ix >= num_materials) {
  17535. face_material[i] = 0;
  17536. mat_ix = 0;
  17537. }
  17538. }
  17539. if (parts) {
  17540. ufbxi_mesh_part_add_face(&parts[mat_ix], face.num_indices);
  17541. }
  17542. }
  17543. if (parts) {
  17544. // Allocate per-material buffers (clear `num_faces` to 0 to re-use it as
  17545. // an index when fetching the face indices).
  17546. uint32_t part_index = 0;
  17547. ufbxi_for(ufbx_mesh_part, part, parts, num_parts) {
  17548. part->index = part_index++;
  17549. part->face_indices.count = part->num_faces;
  17550. part->face_indices.data = ufbxi_push(buf, uint32_t, part->num_faces);
  17551. ufbxi_check_err(error, part->face_indices.data);
  17552. part->num_faces = 0;
  17553. }
  17554. // Fetch the per-material face indices
  17555. ufbxi_nounroll for (size_t i = 0; i < num_faces; i++) {
  17556. uint32_t mat_ix = face_material ? face_material[i] : 0;
  17557. if (mat_ix < num_parts) {
  17558. ufbx_mesh_part *part = &parts[mat_ix];
  17559. part->face_indices.data[part->num_faces++] = (uint32_t)i;
  17560. }
  17561. }
  17562. mesh->material_part_usage_order.count = num_parts;
  17563. mesh->material_part_usage_order.data = ufbxi_push(buf, uint32_t, num_parts);
  17564. ufbxi_check_err(error, mesh->material_part_usage_order.data);
  17565. for (size_t i = 0; i < num_parts; i++) {
  17566. mesh->material_part_usage_order.data[i] = (uint32_t)i;
  17567. }
  17568. ufbxi_unstable_sort(mesh->material_part_usage_order.data, num_parts, sizeof(uint32_t), &ufbxi_material_part_usage_less, parts);
  17569. }
  17570. return 1;
  17571. }
  17572. typedef struct {
  17573. ufbxi_refcount refcount;
  17574. ufbx_anim anim;
  17575. uint32_t magic;
  17576. } ufbxi_anim_imp;
  17577. ufbxi_nodiscard ufbxi_noinline static int ufbxi_push_anim(ufbxi_context *uc, ufbx_anim **p_anim, ufbx_anim_layer **layers, size_t num_layers)
  17578. {
  17579. ufbx_anim *anim = ufbxi_push_zero(&uc->result, ufbx_anim, 1);
  17580. ufbxi_check(anim);
  17581. anim->layers.data = layers;
  17582. anim->layers.count = num_layers;
  17583. *p_anim = anim;
  17584. return 1;
  17585. }
  17586. ufbxi_nodiscard ufbxi_noinline static int ufbxi_finalize_scene(ufbxi_context *uc)
  17587. {
  17588. size_t num_elements = uc->num_elements;
  17589. uc->scene.elements.count = num_elements;
  17590. uc->scene.elements.data = ufbxi_push(&uc->result, ufbx_element*, num_elements);
  17591. ufbxi_check(uc->scene.elements.data);
  17592. uc->scene.metadata.element_buffer_size = uc->tmp_element_byte_offset;
  17593. char *element_data = (char*)ufbxi_push_pop(&uc->result, &uc->tmp_elements, uint64_t, uc->tmp_element_byte_offset/8);
  17594. ufbxi_check(element_data);
  17595. size_t *element_offsets = ufbxi_push_pop(&uc->tmp, &uc->tmp_element_offsets, size_t, uc->tmp_element_offsets.num_items);
  17596. ufbxi_buf_free(&uc->tmp_element_offsets);
  17597. ufbxi_check(element_offsets);
  17598. for (size_t i = 0; i < num_elements; i++) {
  17599. ufbx_element *element = (ufbx_element*)(element_data + element_offsets[i]);
  17600. if (element->type == UFBX_ELEMENT_NODE) {
  17601. ufbx_node *node = (ufbx_node*)element;
  17602. if (node->scale_helper) {
  17603. ufbxi_node_extra *extra = (ufbxi_node_extra*)ufbxi_get_element_extra(uc, node->element_id);
  17604. ufbx_assert(extra);
  17605. node->scale_helper = (ufbx_node*)(element_data + element_offsets[extra->scale_helper_id]);
  17606. }
  17607. }
  17608. uc->scene.elements.data[i] = element;
  17609. }
  17610. uc->scene.elements.count = num_elements;
  17611. ufbxi_buf_free(&uc->tmp_element_offsets);
  17612. ufbxi_buf_free(&uc->tmp_elements);
  17613. uc->tmp_element_flag = ufbxi_push_zero(&uc->tmp, uint8_t, num_elements);
  17614. ufbxi_check(uc->tmp_element_flag);
  17615. uc->scene.metadata.original_file_path = ufbx_find_string(&uc->scene.metadata.scene_props, "DocumentUrl", ufbx_empty_string);
  17616. uc->scene.metadata.raw_original_file_path = ufbx_find_blob(&uc->scene.metadata.scene_props, "DocumentUrl", ufbx_empty_blob);
  17617. // Resolve and add the connections to elements
  17618. ufbxi_check(ufbxi_resolve_connections(uc));
  17619. ufbxi_check(ufbxi_add_connections_to_elements(uc));
  17620. ufbxi_check(ufbxi_linearize_nodes(uc));
  17621. for (size_t type = 0; type < UFBX_ELEMENT_TYPE_COUNT; type++) {
  17622. size_t num_typed = uc->tmp_typed_element_offsets[type].num_items;
  17623. size_t *typed_offsets = ufbxi_push_pop(&uc->tmp, &uc->tmp_typed_element_offsets[type], size_t, num_typed);
  17624. ufbxi_buf_free(&uc->tmp_typed_element_offsets[type]);
  17625. ufbxi_check(typed_offsets);
  17626. ufbx_element_list *typed_elems = &uc->scene.elements_by_type[type];
  17627. typed_elems->count = num_typed;
  17628. typed_elems->data = ufbxi_push(&uc->result, ufbx_element*, num_typed);
  17629. ufbxi_check(typed_elems->data);
  17630. for (size_t i = 0; i < num_typed; i++) {
  17631. typed_elems->data[i] = (ufbx_element*)(element_data + typed_offsets[i]);
  17632. }
  17633. ufbxi_buf_free(&uc->tmp_typed_element_offsets[type]);
  17634. }
  17635. // Create named elements
  17636. uc->scene.elements_by_name.count = num_elements;
  17637. uc->scene.elements_by_name.data = ufbxi_push(&uc->result, ufbx_name_element, num_elements);
  17638. ufbxi_check(uc->scene.elements_by_name.data);
  17639. for (size_t i = 0; i < num_elements; i++) {
  17640. ufbx_element *elem = uc->scene.elements.data[i];
  17641. ufbx_name_element *name_elem = &uc->scene.elements_by_name.data[i];
  17642. name_elem->name = elem->name;
  17643. name_elem->type = elem->type;
  17644. name_elem->_internal_key = ufbxi_get_name_key(elem->name.data, elem->name.length);
  17645. name_elem->element = elem;
  17646. }
  17647. ufbxi_check(ufbxi_sort_name_elements(uc, uc->scene.elements_by_name.data, num_elements));
  17648. // Setup node children arrays and attribute pointers/lists
  17649. ufbxi_for_ptr_list(ufbx_node, p_node, uc->scene.nodes) {
  17650. ufbx_node *node = *p_node, *parent = node->parent;
  17651. if (parent) {
  17652. parent->children.count++;
  17653. if (parent->children.data == NULL) {
  17654. parent->children.data = p_node;
  17655. }
  17656. if (node->is_geometry_transform_helper) {
  17657. parent->geometry_transform_helper = node;
  17658. }
  17659. // Force top-level nodes to have `UFBX_INHERIT_MODE_NORMAL` to make unit scaling work.
  17660. if (parent->is_root && uc->opts.space_conversion == UFBX_SPACE_CONVERSION_TRANSFORM_ROOT && uc->opts.inherit_mode_handling == UFBX_INHERIT_MODE_HANDLING_PRESERVE) {
  17661. node->original_inherit_mode = UFBX_INHERIT_MODE_NORMAL;
  17662. node->inherit_mode = UFBX_INHERIT_MODE_NORMAL;
  17663. }
  17664. // RrSs nodes inherit scale from their parent, Rrs ignore the scale of
  17665. // their _immediate_ parent, potentially multiple if chained.
  17666. if (node->original_inherit_mode == UFBX_INHERIT_MODE_COMPONENTWISE_SCALE) {
  17667. node->inherit_scale_node = parent;
  17668. } else if (node->original_inherit_mode == UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE) {
  17669. node->inherit_scale_node = parent->inherit_scale_node;
  17670. }
  17671. }
  17672. ufbx_connection_list conns = ufbxi_find_dst_connections(&node->element, NULL);
  17673. ufbxi_for_list(ufbx_connection, conn, conns) {
  17674. ufbx_element *elem = conn->src;
  17675. ufbx_element_type type = elem->type;
  17676. if (!(type >= UFBX_ELEMENT_TYPE_FIRST_ATTRIB && type <= UFBX_ELEMENT_TYPE_LAST_ATTRIB)) continue;
  17677. size_t index = node->all_attribs.count++;
  17678. if (index == 0) {
  17679. node->attrib = elem;
  17680. node->attrib_type = type;
  17681. } else {
  17682. if (index == 1) {
  17683. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_element*, 1, &node->attrib));
  17684. }
  17685. ufbxi_check(ufbxi_push_copy(&uc->tmp_stack, ufbx_element*, 1, &elem));
  17686. }
  17687. switch (elem->type) {
  17688. case UFBX_ELEMENT_MESH: node->mesh = (ufbx_mesh*)elem; break;
  17689. case UFBX_ELEMENT_LIGHT: node->light = (ufbx_light*)elem; break;
  17690. case UFBX_ELEMENT_CAMERA: node->camera = (ufbx_camera*)elem; break;
  17691. case UFBX_ELEMENT_BONE: node->bone = (ufbx_bone*)elem; break;
  17692. default: /* No shorthand */ break;
  17693. }
  17694. }
  17695. if (node->all_attribs.count > 1) {
  17696. node->all_attribs.data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_element*, node->all_attribs.count);
  17697. ufbxi_check(node->all_attribs.data);
  17698. } else if (node->all_attribs.count == 1) {
  17699. node->all_attribs.data = &node->attrib;
  17700. }
  17701. ufbxi_check(ufbxi_fetch_dst_elements(uc, &node->materials, &node->element, false, false, NULL, UFBX_ELEMENT_MATERIAL));
  17702. }
  17703. // Resolve bind pose bones that don't use the normal connection system
  17704. ufbxi_for_ptr_list(ufbx_pose, p_pose, uc->scene.poses) {
  17705. ufbx_pose *pose = *p_pose;
  17706. // HACK: Transport `ufbxi_tmp_bone_pose` array through the `ufbx_bone_pose` pointer
  17707. size_t num_bones = pose->bone_poses.count;
  17708. ufbxi_tmp_bone_pose *tmp_poses = (ufbxi_tmp_bone_pose*)pose->bone_poses.data;
  17709. pose->bone_poses.data = ufbxi_push(&uc->result, ufbx_bone_pose, num_bones);
  17710. ufbxi_check(pose->bone_poses.data);
  17711. // Filter only found bones
  17712. pose->bone_poses.count = 0;
  17713. for (size_t i = 0; i < num_bones; i++) {
  17714. ufbx_element *elem = ufbxi_find_element_by_fbx_id(uc, tmp_poses[i].bone_fbx_id);
  17715. if (!elem || elem->type != UFBX_ELEMENT_NODE) continue;
  17716. ufbx_node *node = (ufbx_node*)elem;
  17717. ufbx_bone_pose *bone = &pose->bone_poses.data[pose->bone_poses.count++];
  17718. bone->bone_node = node;
  17719. bone->bone_to_world = tmp_poses[i].bone_to_world;
  17720. if (pose->is_bind_pose) {
  17721. if (node->bind_pose == NULL) {
  17722. node->bind_pose = pose;
  17723. }
  17724. ufbx_connection_list node_conns = ufbxi_find_src_connections(elem, NULL);
  17725. ufbxi_for_list(ufbx_connection, conn, node_conns) {
  17726. if (conn->dst->type != UFBX_ELEMENT_SKIN_CLUSTER) continue;
  17727. ufbx_skin_cluster *cluster = (ufbx_skin_cluster*)conn->dst;
  17728. if (ufbxi_matrix_all_zero(&cluster->bind_to_world)) {
  17729. cluster->bind_to_world = bone->bone_to_world;
  17730. }
  17731. }
  17732. }
  17733. }
  17734. ufbxi_check(ufbxi_sort_bone_poses(uc, pose));
  17735. }
  17736. // Fetch pointers that may break elements
  17737. // Setup node attribute instances
  17738. for (int type = UFBX_ELEMENT_TYPE_FIRST_ATTRIB; type <= UFBX_ELEMENT_TYPE_LAST_ATTRIB; type++) {
  17739. ufbxi_for_ptr_list(ufbx_element, p_elem, uc->scene.elements_by_type[type]) {
  17740. ufbx_element *elem = *p_elem;
  17741. ufbxi_check(ufbxi_fetch_src_elements(uc, &elem->instances, elem, false, true, NULL, UFBX_ELEMENT_NODE));
  17742. }
  17743. }
  17744. bool search_node = uc->version < 7000;
  17745. ufbxi_for_ptr_list(ufbx_skin_cluster, p_cluster, uc->scene.skin_clusters) {
  17746. ufbx_skin_cluster *cluster = *p_cluster;
  17747. cluster->bone_node = (ufbx_node*)ufbxi_fetch_dst_element(&cluster->element, false, NULL, UFBX_ELEMENT_NODE);
  17748. }
  17749. ufbxi_for_ptr_list(ufbx_skin_deformer, p_skin, uc->scene.skin_deformers) {
  17750. ufbx_skin_deformer *skin = *p_skin;
  17751. ufbxi_check(ufbxi_fetch_dst_elements(uc, &skin->clusters, &skin->element, false, true, NULL, UFBX_ELEMENT_SKIN_CLUSTER));
  17752. // Remove clusters without a valid `bone`
  17753. if (!uc->opts.connect_broken_elements) {
  17754. size_t num_broken = 0;
  17755. for (size_t i = 0; i < skin->clusters.count; i++) {
  17756. if (!skin->clusters.data[i]->bone_node) {
  17757. num_broken++;
  17758. } else if (num_broken > 0) {
  17759. skin->clusters.data[i - num_broken] = skin->clusters.data[i];
  17760. }
  17761. }
  17762. skin->clusters.count -= num_broken;
  17763. }
  17764. size_t total_weights = 0;
  17765. ufbxi_for_ptr_list(ufbx_skin_cluster, p_cluster, skin->clusters) {
  17766. ufbx_skin_cluster *cluster = *p_cluster;
  17767. ufbxi_check(SIZE_MAX - total_weights > cluster->num_weights);
  17768. total_weights += cluster->num_weights;
  17769. }
  17770. size_t num_vertices = 0;
  17771. // Iterate through meshes so we can pad the vertices to the largest one
  17772. {
  17773. ufbx_connection_list conns = ufbxi_find_src_connections(&skin->element, NULL);
  17774. ufbxi_for_list(ufbx_connection, conn, conns) {
  17775. ufbx_mesh *mesh = NULL;
  17776. if (conn->dst_prop.length > 0) continue;
  17777. if (conn->dst->type == UFBX_ELEMENT_MESH) {
  17778. mesh = (ufbx_mesh*)conn->dst;
  17779. } else if (conn->dst->type == UFBX_ELEMENT_NODE) {
  17780. ufbx_node *node = (ufbx_node*)conn->dst;
  17781. if (node->geometry_transform_helper) node = node->geometry_transform_helper;
  17782. mesh = node->mesh;
  17783. }
  17784. if (!mesh) continue;
  17785. num_vertices = ufbxi_max_sz(num_vertices, mesh->num_vertices);
  17786. }
  17787. }
  17788. if (!uc->opts.skip_skin_vertices) {
  17789. skin->vertices.count = num_vertices;
  17790. skin->vertices.data = ufbxi_push_zero(&uc->result, ufbx_skin_vertex, num_vertices);
  17791. ufbxi_check(skin->vertices.data);
  17792. skin->weights.count = total_weights;
  17793. skin->weights.data = ufbxi_push_zero(&uc->result, ufbx_skin_weight, total_weights);
  17794. ufbxi_check(skin->weights.data);
  17795. bool retain_all = !uc->opts.clean_skin_weights;
  17796. // Count the number of weights per vertex
  17797. ufbxi_for_ptr_list(ufbx_skin_cluster, p_cluster, skin->clusters) {
  17798. ufbx_skin_cluster *cluster = *p_cluster;
  17799. for (size_t i = 0; i < cluster->num_weights; i++) {
  17800. uint32_t vertex = cluster->vertices.data[i];
  17801. if (vertex < num_vertices && (retain_all || cluster->weights.data[i] > 0.0f)) {
  17802. skin->vertices.data[vertex].num_weights++;
  17803. }
  17804. }
  17805. }
  17806. ufbx_real default_dq = skin->skinning_method == UFBX_SKINNING_METHOD_DUAL_QUATERNION ? 1.0f : 0.0f;
  17807. // Prefix sum to assign the vertex weight offsets and set up default DQ values
  17808. uint32_t offset = 0;
  17809. uint32_t max_weights = 0;
  17810. for (size_t i = 0; i < num_vertices; i++) {
  17811. skin->vertices.data[i].weight_begin = offset;
  17812. skin->vertices.data[i].dq_weight = default_dq;
  17813. uint32_t num_weights = skin->vertices.data[i].num_weights;
  17814. offset += num_weights;
  17815. skin->vertices.data[i].num_weights = 0;
  17816. if (num_weights > max_weights) max_weights = num_weights;
  17817. }
  17818. ufbx_assert(offset <= total_weights);
  17819. skin->max_weights_per_vertex = max_weights;
  17820. // Copy the DQ weights to vertices
  17821. for (size_t i = 0; i < skin->num_dq_weights; i++) {
  17822. uint32_t vertex = skin->dq_vertices.data[i];
  17823. if (vertex < num_vertices) {
  17824. skin->vertices.data[vertex].dq_weight = skin->dq_weights.data[i];
  17825. }
  17826. }
  17827. // Copy the weights to vertices
  17828. uint32_t cluster_index = 0;
  17829. ufbxi_for_ptr_list(ufbx_skin_cluster, p_cluster, skin->clusters) {
  17830. ufbx_skin_cluster *cluster = *p_cluster;
  17831. for (size_t i = 0; i < cluster->num_weights; i++) {
  17832. uint32_t vertex = cluster->vertices.data[i];
  17833. if (vertex < num_vertices && (retain_all || cluster->weights.data[i] > 0.0f)) {
  17834. uint32_t local_index = skin->vertices.data[vertex].num_weights++;
  17835. uint32_t index = skin->vertices.data[vertex].weight_begin + local_index;
  17836. skin->weights.data[index].cluster_index = cluster_index;
  17837. skin->weights.data[index].weight = cluster->weights.data[i];
  17838. }
  17839. }
  17840. cluster_index++;
  17841. }
  17842. // Sort the vertex weights by descending weight value
  17843. ufbxi_check(ufbxi_sort_skin_weights(uc, skin));
  17844. }
  17845. }
  17846. ufbxi_for_ptr_list(ufbx_blend_deformer, p_blend, uc->scene.blend_deformers) {
  17847. ufbx_blend_deformer *blend = *p_blend;
  17848. ufbxi_check(ufbxi_fetch_dst_elements(uc, &blend->channels, &blend->element, false, true, NULL, UFBX_ELEMENT_BLEND_CHANNEL));
  17849. }
  17850. ufbxi_for_ptr_list(ufbx_cache_deformer, p_deformer, uc->scene.cache_deformers) {
  17851. ufbx_cache_deformer *deformer = *p_deformer;
  17852. deformer->channel = ufbx_find_string(&deformer->props, "ChannelName", ufbx_empty_string);
  17853. deformer->file = (ufbx_cache_file*)ufbxi_fetch_dst_element(&deformer->element, false, NULL, UFBX_ELEMENT_CACHE_FILE);
  17854. }
  17855. ufbxi_for_ptr_list(ufbx_cache_file, p_cache, uc->scene.cache_files) {
  17856. ufbx_cache_file *cache = *p_cache;
  17857. cache->absolute_filename = ufbx_find_string(&cache->props, "CacheAbsoluteFileName", ufbx_empty_string);
  17858. cache->relative_filename = ufbx_find_string(&cache->props, "CacheFileName", ufbx_empty_string);
  17859. cache->raw_absolute_filename = ufbx_find_blob(&cache->props, "CacheAbsoluteFileName", ufbx_empty_blob);
  17860. cache->raw_relative_filename = ufbx_find_blob(&cache->props, "CacheFileName", ufbx_empty_blob);
  17861. int64_t type = ufbx_find_int(&cache->props, "CacheFileType", 0);
  17862. if (type >= 0 && type <= UFBX_CACHE_FILE_FORMAT_MC) {
  17863. cache->format = (ufbx_cache_file_format)type;
  17864. }
  17865. ufbxi_check(ufbxi_resolve_filenames(uc, (ufbxi_strblob*)&cache->filename, (ufbxi_strblob*)&cache->absolute_filename, (ufbxi_strblob*)&cache->relative_filename, false));
  17866. ufbxi_check(ufbxi_resolve_filenames(uc, (ufbxi_strblob*)&cache->raw_filename, (ufbxi_strblob*)&cache->raw_absolute_filename, (ufbxi_strblob*)&cache->raw_relative_filename, true));
  17867. }
  17868. ufbx_assert(uc->tmp_full_weights.num_items == uc->scene.blend_channels.count);
  17869. ufbx_real_list *full_weights = ufbxi_push_pop(&uc->tmp, &uc->tmp_full_weights, ufbx_real_list, uc->tmp_full_weights.num_items);
  17870. ufbxi_buf_free(&uc->tmp_full_weights);
  17871. ufbxi_check(full_weights);
  17872. ufbxi_for_ptr_list(ufbx_blend_channel, p_channel, uc->scene.blend_channels) {
  17873. ufbx_blend_channel *channel = *p_channel;
  17874. ufbxi_check(ufbxi_fetch_blend_keyframes(uc, &channel->keyframes, &channel->element));
  17875. for (size_t i = 0; i < channel->keyframes.count; i++) {
  17876. ufbx_blend_keyframe *key = &channel->keyframes.data[i];
  17877. if (i < full_weights->count) {
  17878. key->target_weight = full_weights->data[i] / (ufbx_real)100.0;
  17879. } else {
  17880. key->target_weight = 1.0f;
  17881. }
  17882. }
  17883. ufbxi_check(ufbxi_sort_blend_keyframes(uc, channel->keyframes.data, channel->keyframes.count));
  17884. full_weights++;
  17885. if (channel->keyframes.count > 0) {
  17886. channel->target_shape = channel->keyframes.data[channel->keyframes.count - 1].shape;
  17887. }
  17888. }
  17889. ufbxi_buf_free(&uc->tmp_full_weights);
  17890. {
  17891. // Generate and patch procedural index buffers
  17892. uint32_t *zero_indices = ufbxi_push(&uc->result, uint32_t, uc->max_zero_indices);
  17893. uint32_t *consecutive_indices = ufbxi_push(&uc->result, uint32_t, uc->max_consecutive_indices);
  17894. ufbxi_check(zero_indices && consecutive_indices);
  17895. memset(zero_indices, 0, sizeof(uint32_t) * uc->max_zero_indices);
  17896. for (size_t i = 0; i < uc->max_consecutive_indices; i++) {
  17897. consecutive_indices[i] = (uint32_t)i;
  17898. }
  17899. uc->zero_indices = zero_indices;
  17900. uc->consecutive_indices = consecutive_indices;
  17901. ufbxi_for_ptr_list(ufbx_mesh, p_mesh, uc->scene.meshes) {
  17902. ufbx_mesh *mesh = *p_mesh;
  17903. ufbxi_patch_index_pointer(uc, &mesh->vertex_position.indices.data);
  17904. ufbxi_patch_index_pointer(uc, &mesh->vertex_normal.indices.data);
  17905. ufbxi_patch_index_pointer(uc, &mesh->vertex_color.indices.data);
  17906. ufbxi_patch_index_pointer(uc, &mesh->vertex_crease.indices.data);
  17907. ufbxi_patch_index_pointer(uc, &mesh->face_material.data);
  17908. ufbxi_patch_index_pointer(uc, &mesh->face_group.data);
  17909. ufbxi_patch_index_pointer(uc, &mesh->skinned_position.indices.data);
  17910. ufbxi_patch_index_pointer(uc, &mesh->skinned_normal.indices.data);
  17911. ufbxi_for_list(ufbx_uv_set, set, mesh->uv_sets) {
  17912. ufbxi_patch_index_pointer(uc, &set->vertex_uv.indices.data);
  17913. ufbxi_patch_index_pointer(uc, &set->vertex_bitangent.indices.data);
  17914. ufbxi_patch_index_pointer(uc, &set->vertex_tangent.indices.data);
  17915. }
  17916. ufbxi_for_list(ufbx_color_set, set, mesh->color_sets) {
  17917. ufbxi_patch_index_pointer(uc, &set->vertex_color.indices.data);
  17918. }
  17919. // Generate normals if necessary
  17920. if (!mesh->vertex_normal.exists && uc->opts.generate_missing_normals) {
  17921. ufbxi_check(ufbxi_generate_normals(uc, mesh));
  17922. }
  17923. // Assign first UV and color sets as the "canonical" ones
  17924. if (mesh->uv_sets.count > 0) {
  17925. mesh->vertex_uv = mesh->uv_sets.data[0].vertex_uv;
  17926. mesh->vertex_bitangent = mesh->uv_sets.data[0].vertex_bitangent;
  17927. mesh->vertex_tangent = mesh->uv_sets.data[0].vertex_tangent;
  17928. }
  17929. if (mesh->color_sets.count > 0) {
  17930. mesh->vertex_color = mesh->color_sets.data[0].vertex_color;
  17931. }
  17932. if (mesh->face_group_parts.count == 1) {
  17933. ufbxi_patch_index_pointer(uc, &mesh->face_group_parts.data[0].face_indices.data);
  17934. }
  17935. ufbxi_check(ufbxi_fetch_mesh_materials(uc, &mesh->materials, &mesh->element, true));
  17936. // Patch materials to instances if necessary
  17937. if (mesh->materials.count > 0) {
  17938. ufbxi_for_ptr_list(ufbx_node, p_node, mesh->instances) {
  17939. ufbx_node *node = *p_node;
  17940. if (node->materials.count < mesh->materials.count && mesh->materials.data[0] != NULL) {
  17941. ufbx_material **materials = ufbxi_push(&uc->result, ufbx_material*, mesh->materials.count);
  17942. ufbxi_check(materials);
  17943. ufbxi_nounroll for (size_t i = 0; i < node->materials.count; i++) {
  17944. materials[i] = node->materials.data[i];
  17945. }
  17946. ufbxi_nounroll for (size_t i = node->materials.count; i < mesh->materials.count; i++) {
  17947. materials[i] = mesh->materials.data[i];
  17948. }
  17949. node->materials.data = materials;
  17950. node->materials.count = mesh->materials.count;
  17951. }
  17952. }
  17953. }
  17954. if (uc->retain_mesh_parts) {
  17955. size_t num_parts = ufbxi_max_sz(mesh->materials.count, 1);
  17956. mesh->material_parts.data = ufbxi_push_zero(&uc->result, ufbx_mesh_part, num_parts);
  17957. ufbxi_check(mesh->material_parts.data);
  17958. mesh->material_parts.count = num_parts;
  17959. }
  17960. if (mesh->materials.count <= 1) {
  17961. // Use the shared consecutive index buffer for mesh faces if there's only one material
  17962. // See HACK(consecutive-faces) in `ufbxi_read_mesh()`.
  17963. if (mesh->material_parts.count > 0) {
  17964. ufbx_mesh_part *part = &mesh->material_parts.data[0];
  17965. part->num_faces = mesh->num_faces;
  17966. part->num_triangles = mesh->num_triangles;
  17967. part->num_empty_faces = mesh->num_empty_faces;
  17968. part->num_point_faces = mesh->num_point_faces;
  17969. part->num_line_faces = mesh->num_line_faces;
  17970. part->face_indices.data = uc->consecutive_indices;
  17971. part->face_indices.count = mesh->num_faces;
  17972. mesh->material_part_usage_order.data = uc->zero_indices;
  17973. mesh->material_part_usage_order.count = 1;
  17974. }
  17975. if (mesh->materials.count == 1) {
  17976. mesh->face_material.data = uc->zero_indices;
  17977. mesh->face_material.count = mesh->num_faces;
  17978. } else {
  17979. mesh->face_material.data = NULL;
  17980. mesh->face_material.count = 0;
  17981. }
  17982. } else if (mesh->materials.count > 0) {
  17983. ufbxi_check(ufbxi_finalize_mesh_material(&uc->result, &uc->error, mesh));
  17984. }
  17985. // Fetch deformers
  17986. ufbxi_check(ufbxi_fetch_dst_elements(uc, &mesh->skin_deformers, &mesh->element, search_node, true, NULL, UFBX_ELEMENT_SKIN_DEFORMER));
  17987. ufbxi_check(ufbxi_fetch_dst_elements(uc, &mesh->blend_deformers, &mesh->element, search_node, true, NULL, UFBX_ELEMENT_BLEND_DEFORMER));
  17988. ufbxi_check(ufbxi_fetch_dst_elements(uc, &mesh->cache_deformers, &mesh->element, search_node, true, NULL, UFBX_ELEMENT_CACHE_DEFORMER));
  17989. ufbxi_check(ufbxi_fetch_deformers(uc, &mesh->all_deformers, &mesh->element, search_node));
  17990. // Vertex position must always exist if not explicitly allowed to be missing
  17991. if (!mesh->vertex_position.exists && !uc->opts.allow_missing_vertex_position) {
  17992. ufbxi_check(mesh->num_indices == 0);
  17993. mesh->vertex_position.exists = true;
  17994. mesh->vertex_position.unique_per_vertex = true;
  17995. mesh->skinned_position.exists = true;
  17996. mesh->skinned_position.unique_per_vertex = true;
  17997. }
  17998. // Update metadata
  17999. if (mesh->max_face_triangles > uc->scene.metadata.max_face_triangles) {
  18000. uc->scene.metadata.max_face_triangles = mesh->max_face_triangles;
  18001. }
  18002. }
  18003. }
  18004. ufbxi_for_ptr_list(ufbx_stereo_camera, p_stereo, uc->scene.stereo_cameras) {
  18005. ufbx_stereo_camera *stereo = *p_stereo;
  18006. stereo->left = (ufbx_camera*)ufbxi_fetch_dst_element(&stereo->element, search_node, ufbxi_LeftCamera, UFBX_ELEMENT_CAMERA);
  18007. stereo->right = (ufbx_camera*)ufbxi_fetch_dst_element(&stereo->element, search_node, ufbxi_RightCamera, UFBX_ELEMENT_CAMERA);
  18008. }
  18009. ufbxi_for_ptr_list(ufbx_nurbs_curve, p_curve, uc->scene.nurbs_curves) {
  18010. ufbx_nurbs_curve *curve = *p_curve;
  18011. ufbxi_check(ufbxi_finalize_nurbs_basis(uc, &curve->basis));
  18012. }
  18013. ufbxi_for_ptr_list(ufbx_nurbs_surface, p_surface, uc->scene.nurbs_surfaces) {
  18014. ufbx_nurbs_surface *surface = *p_surface;
  18015. ufbxi_check(ufbxi_finalize_nurbs_basis(uc, &surface->basis_u));
  18016. ufbxi_check(ufbxi_finalize_nurbs_basis(uc, &surface->basis_v));
  18017. surface->material = (ufbx_material*)ufbxi_fetch_dst_element(&surface->element, true, NULL, UFBX_ELEMENT_MATERIAL);
  18018. }
  18019. ufbxi_for_ptr_list(ufbx_anim_stack, p_stack, uc->scene.anim_stacks) {
  18020. ufbx_anim_stack *stack = *p_stack;
  18021. ufbxi_check(ufbxi_fetch_dst_elements(uc, &stack->layers, &stack->element, false, true, NULL, UFBX_ELEMENT_ANIM_LAYER));
  18022. ufbxi_check(ufbxi_push_anim(uc, &stack->anim, stack->layers.data, stack->layers.count));
  18023. }
  18024. ufbxi_for_ptr_list(ufbx_anim_layer, p_layer, uc->scene.anim_layers) {
  18025. ufbx_anim_layer *layer = *p_layer;
  18026. ufbxi_check(ufbxi_fetch_dst_elements(uc, &layer->anim_values, &layer->element, false, true, NULL, UFBX_ELEMENT_ANIM_VALUE));
  18027. ufbxi_check(ufbxi_push_anim(uc, &layer->anim, p_layer, 1));
  18028. uint32_t min_id = UINT32_MAX, max_id = 0;
  18029. // Combine the animated properties with elements (potentially duplicates!)
  18030. size_t num_anim_props = 0;
  18031. ufbxi_for_ptr_list(ufbx_anim_value, p_value, layer->anim_values) {
  18032. ufbx_anim_value *value = *p_value;
  18033. ufbxi_for_list(ufbx_connection, ac, value->element.connections_src) {
  18034. if (ac->src_prop.length == 0 && ac->dst_prop.length > 0) {
  18035. ufbx_anim_prop *aprop = ufbxi_push(&uc->tmp_stack, ufbx_anim_prop, 1);
  18036. uint32_t id = ac->dst->element_id;
  18037. min_id = ufbxi_min32(min_id, id);
  18038. max_id = ufbxi_max32(max_id, id);
  18039. uint32_t id_mask = ufbxi_arraycount(layer->_element_id_bitmask) - 1;
  18040. layer->_element_id_bitmask[(id >> 5) & id_mask] |= 1u << (id & 31);
  18041. ufbxi_check(aprop);
  18042. aprop->anim_value = value;
  18043. aprop->element = ac->dst;
  18044. aprop->_internal_key = ufbxi_get_name_key(ac->dst_prop.data, ac->dst_prop.length);
  18045. aprop->prop_name = ac->dst_prop;
  18046. num_anim_props++;
  18047. }
  18048. }
  18049. }
  18050. if (min_id != UINT32_MAX) {
  18051. layer->_min_element_id = min_id;
  18052. layer->_max_element_id = max_id;
  18053. }
  18054. switch (ufbxi_find_int(&layer->props, ufbxi_BlendMode, 0)) {
  18055. case 0: // Additive
  18056. layer->blended = true;
  18057. layer->additive = true;
  18058. break;
  18059. case 1: // Override
  18060. layer->blended = false;
  18061. layer->additive = false;
  18062. break;
  18063. case 2: // Override Passthrough
  18064. layer->blended = true;
  18065. layer->additive = false;
  18066. break;
  18067. default: // Unknown
  18068. layer->blended = false;
  18069. layer->additive = false;
  18070. break;
  18071. }
  18072. ufbx_prop *weight_prop = ufbxi_find_prop(&layer->props, ufbxi_Weight);
  18073. if (weight_prop) {
  18074. layer->weight = weight_prop->value_real / (ufbx_real)100.0;
  18075. if (layer->weight < 0.0f) layer->weight = 0.0f;
  18076. if (layer->weight > 0.99999f) layer->weight = 1.0f;
  18077. layer->weight_is_animated = (weight_prop->flags & UFBX_PROP_FLAG_ANIMATED) != 0;
  18078. } else {
  18079. layer->weight = 1.0f;
  18080. layer->weight_is_animated = false;
  18081. }
  18082. layer->compose_rotation = ufbxi_find_int(&layer->props, ufbxi_RotationAccumulationMode, 0) == 0;
  18083. layer->compose_scale = ufbxi_find_int(&layer->props, ufbxi_ScaleAccumulationMode, 0) == 0;
  18084. // Add a dummy NULL element animated prop at the end so we can iterate
  18085. // animated props without worrying about boundary conditions..
  18086. {
  18087. ufbx_anim_prop *aprop = ufbxi_push_zero(&uc->tmp_stack, ufbx_anim_prop, 1);
  18088. ufbxi_check(aprop);
  18089. }
  18090. layer->anim_props.data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_anim_prop, num_anim_props + 1);
  18091. ufbxi_check(layer->anim_props.data);
  18092. layer->anim_props.count = num_anim_props;
  18093. ufbxi_check(ufbxi_sort_anim_props(uc, layer->anim_props.data, layer->anim_props.count));
  18094. }
  18095. ufbxi_for_ptr_list(ufbx_anim_value, p_value, uc->scene.anim_values) {
  18096. ufbx_anim_value *value = *p_value;
  18097. // TODO: Search for things like d|Visibility with a constructed name
  18098. value->default_value.x = ufbxi_find_real(&value->props, ufbxi_X, value->default_value.x);
  18099. value->default_value.x = ufbxi_find_real(&value->props, ufbxi_d_X, value->default_value.x);
  18100. value->default_value.y = ufbxi_find_real(&value->props, ufbxi_Y, value->default_value.y);
  18101. value->default_value.y = ufbxi_find_real(&value->props, ufbxi_d_Y, value->default_value.y);
  18102. value->default_value.z = ufbxi_find_real(&value->props, ufbxi_Z, value->default_value.z);
  18103. value->default_value.z = ufbxi_find_real(&value->props, ufbxi_d_Z, value->default_value.z);
  18104. ufbxi_for_list(ufbx_connection, conn, value->element.connections_dst) {
  18105. if (conn->src->type == UFBX_ELEMENT_ANIM_CURVE && conn->src_prop.length == 0) {
  18106. ufbx_anim_curve *curve = (ufbx_anim_curve*)conn->src;
  18107. uint32_t index = 0;
  18108. const char *name = conn->dst_prop.data;
  18109. if (name == ufbxi_Y || name == ufbxi_d_Y) index = 1;
  18110. if (name == ufbxi_Z || name == ufbxi_d_Z) index = 2;
  18111. ufbx_prop *prop = ufbx_find_prop_len(&value->props, conn->dst_prop.data, conn->dst_prop.length);
  18112. if (prop) {
  18113. value->default_value.v[index] = prop->value_real;
  18114. }
  18115. value->curves[index] = curve;
  18116. }
  18117. }
  18118. }
  18119. ufbxi_for_ptr_list(ufbx_shader, p_shader, uc->scene.shaders) {
  18120. ufbx_shader *shader = *p_shader;
  18121. ufbxi_check(ufbxi_fetch_dst_elements(uc, &shader->bindings, &shader->element, false, false, NULL, UFBX_ELEMENT_SHADER_BINDING));
  18122. ufbx_prop *api = ufbx_find_prop(&shader->props, "RenderAPI");
  18123. if (api) {
  18124. if (!strcmp(api->value_str.data, "ARNOLD_SHADER_ID")) {
  18125. shader->type = UFBX_SHADER_ARNOLD_STANDARD_SURFACE;
  18126. } else if (!strcmp(api->value_str.data, "OSL")) {
  18127. shader->type = UFBX_SHADER_OSL_STANDARD_SURFACE;
  18128. } else if (!strcmp(api->value_str.data, "SFX_PBS_SHADER")) {
  18129. shader->type = UFBX_SHADER_SHADERFX_GRAPH;
  18130. }
  18131. }
  18132. }
  18133. ufbxi_for_ptr_list(ufbx_material, p_material, uc->scene.materials) {
  18134. ufbx_material *material = *p_material;
  18135. material->shader = (ufbx_shader*)ufbxi_fetch_src_element(&material->element, false, NULL, UFBX_ELEMENT_SHADER);
  18136. if (!strcmp(material->shading_model_name.data, "lambert") || !strcmp(material->shading_model_name.data, "Lambert")) {
  18137. material->shader_type = UFBX_SHADER_FBX_LAMBERT;
  18138. } else if (!strcmp(material->shading_model_name.data, "phong") || !strcmp(material->shading_model_name.data, "Phong")) {
  18139. material->shader_type = UFBX_SHADER_FBX_PHONG;
  18140. }
  18141. if (material->shader) {
  18142. material->shader_type = material->shader->type;
  18143. } else {
  18144. if (uc->opts.use_blender_pbr_material && uc->exporter == UFBX_EXPORTER_BLENDER_BINARY && uc->exporter_version >= ufbx_pack_version(4,12,0)) {
  18145. material->shader_type = UFBX_SHADER_BLENDER_PHONG;
  18146. }
  18147. // TODO: Is this too strict?
  18148. if (material->shader_type == UFBX_SHADER_UNKNOWN) {
  18149. uint32_t classid_a = (uint32_t)(uint64_t)ufbx_find_int(&material->props, "3dsMax|ClassIDa", 0);
  18150. uint32_t classid_b = (uint32_t)(uint64_t)ufbx_find_int(&material->props, "3dsMax|ClassIDb", 0);
  18151. if (classid_a == 0x3d6b1cecu && classid_b == 0xdeadc001u) {
  18152. material->shader_type = UFBX_SHADER_3DS_MAX_PHYSICAL_MATERIAL;
  18153. material->shader_prop_prefix.data = "3dsMax|Parameters|";
  18154. material->shader_prop_prefix.length = strlen("3dsMax|Parameters|");
  18155. } else if (classid_a == 0x38420192u && classid_b == 0x45fe4e1bu) {
  18156. material->shader_type = UFBX_SHADER_GLTF_MATERIAL;
  18157. material->shader_prop_prefix.data = "3dsMax|";
  18158. material->shader_prop_prefix.length = strlen("3dsMax|");
  18159. } else if (classid_a == 0xd00f1e00u && classid_b == 0xbe77e500u) {
  18160. material->shader_type = UFBX_SHADER_3DS_MAX_PBR_METAL_ROUGH;
  18161. material->shader_prop_prefix.data = "3dsMax|main|";
  18162. material->shader_prop_prefix.length = strlen("3dsMax|main|");
  18163. } else if (classid_a == 0xd00f1e00u && classid_b == 0x01dbad33u) {
  18164. material->shader_type = UFBX_SHADER_3DS_MAX_PBR_SPEC_GLOSS;
  18165. material->shader_prop_prefix.data = "3dsMax|main|";
  18166. material->shader_prop_prefix.length = strlen("3dsMax|main|");
  18167. }
  18168. }
  18169. }
  18170. ufbxi_check(ufbxi_fetch_textures(uc, &material->textures, &material->element, false));
  18171. }
  18172. // Ugh.. Patch the textures from meshes for legacy LayerElement-style textures
  18173. {
  18174. ufbxi_for_ptr_list(ufbx_mesh, p_mesh, uc->scene.meshes) {
  18175. ufbx_mesh *mesh = *p_mesh;
  18176. size_t num_materials = mesh->materials.count;
  18177. ufbxi_mesh_extra *extra = (ufbxi_mesh_extra*)ufbxi_get_element_extra(uc, mesh->element.element_id);
  18178. if (!extra) continue;
  18179. if (num_materials == 0) continue;
  18180. // TODO: This leaks currently to result, probably doesn't matter..
  18181. ufbx_texture_list textures;
  18182. ufbxi_check(ufbxi_fetch_dst_elements(uc, &textures, &mesh->element, true, false, NULL, UFBX_ELEMENT_TEXTURE));
  18183. size_t num_material_textures = 0;
  18184. ufbxi_for(ufbxi_tmp_mesh_texture, tex, extra->texture_arr, extra->texture_count) {
  18185. if (tex->all_same) {
  18186. int32_t texture_id = tex->num_faces > 0 ? (int32_t)tex->face_texture[0] : 0;
  18187. if (texture_id >= 0 && (size_t)texture_id < textures.count) {
  18188. ufbxi_tmp_material_texture *mat_texs = ufbxi_push(&uc->tmp_stack, ufbxi_tmp_material_texture, num_materials);
  18189. ufbxi_check(mat_texs);
  18190. num_material_textures += num_materials;
  18191. for (size_t i = 0; i < num_materials; i++) {
  18192. mat_texs[i].material_id = (int32_t)i;
  18193. mat_texs[i].texture_id = texture_id;
  18194. mat_texs[i].prop_name = tex->prop_name;
  18195. }
  18196. }
  18197. } else if (mesh->face_material.count) {
  18198. size_t num_faces = ufbxi_min_sz(tex->num_faces, mesh->num_faces);
  18199. int32_t prev_material = -1;
  18200. int32_t prev_texture = -1;
  18201. for (size_t i = 0; i < num_faces; i++) {
  18202. int32_t texture_id = (int32_t)tex->face_texture[i];
  18203. int32_t material_id = (int32_t)mesh->face_material.data[i];
  18204. if (texture_id < 0 || (size_t)texture_id >= textures.count) continue;
  18205. if (material_id < 0 || (size_t)material_id >= num_materials) continue;
  18206. if (material_id == prev_material && texture_id == prev_texture) continue;
  18207. prev_material = material_id;
  18208. prev_texture = texture_id;
  18209. ufbxi_tmp_material_texture *mat_tex = ufbxi_push(&uc->tmp_stack, ufbxi_tmp_material_texture, 1);
  18210. ufbxi_check(mat_tex);
  18211. mat_tex->material_id = material_id;
  18212. mat_tex->texture_id = texture_id;
  18213. mat_tex->prop_name = tex->prop_name;
  18214. num_material_textures++;
  18215. }
  18216. }
  18217. }
  18218. // Push a sentinel material texture to the end so we don't need to
  18219. // duplicate the material texture flushing code twice.
  18220. {
  18221. ufbxi_tmp_material_texture *mat_tex = ufbxi_push(&uc->tmp_stack, ufbxi_tmp_material_texture, 1);
  18222. ufbxi_check(mat_tex);
  18223. mat_tex->material_id = -1;
  18224. mat_tex->texture_id = -1;
  18225. mat_tex->prop_name = ufbx_empty_string;
  18226. }
  18227. ufbxi_tmp_material_texture *mat_texs = ufbxi_push_pop(&uc->tmp, &uc->tmp_stack, ufbxi_tmp_material_texture, num_material_textures + 1);
  18228. ufbxi_check(mat_texs);
  18229. ufbxi_check(ufbxi_sort_tmp_material_textures(uc, mat_texs, num_material_textures));
  18230. int32_t prev_material = -2;
  18231. int32_t prev_texture = -2;
  18232. const char *prev_prop = NULL;
  18233. size_t num_textures_in_material = 0;
  18234. for (size_t i = 0; i < num_material_textures + 1; i++) {
  18235. ufbxi_tmp_material_texture mat_tex = mat_texs[i];
  18236. if (mat_tex.material_id != prev_material) {
  18237. if (prev_material >= 0 && num_textures_in_material > 0) {
  18238. ufbx_material *mat = mesh->materials.data[prev_material];
  18239. if (mat && mat->textures.count == 0) {
  18240. ufbx_material_texture *texs = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_material_texture, num_textures_in_material);
  18241. ufbxi_check(texs);
  18242. mat->textures.data = texs;
  18243. mat->textures.count = num_textures_in_material;
  18244. } else {
  18245. ufbxi_pop(&uc->tmp_stack, ufbx_material_texture, num_textures_in_material, NULL);
  18246. }
  18247. }
  18248. if (mat_tex.material_id < 0) break;
  18249. prev_material = mat_tex.material_id;
  18250. prev_texture = -1;
  18251. prev_prop = NULL;
  18252. num_textures_in_material = 0;
  18253. }
  18254. if (mat_tex.texture_id == prev_texture && mat_tex.prop_name.data == prev_prop) continue;
  18255. prev_texture = mat_tex.texture_id;
  18256. prev_prop = mat_tex.prop_name.data;
  18257. ufbx_material_texture *tex = ufbxi_push(&uc->tmp_stack, ufbx_material_texture, 1);
  18258. ufbxi_check(tex);
  18259. ufbx_assert(prev_texture >= 0 && (size_t)prev_texture < textures.count);
  18260. tex->texture = textures.data[prev_texture];
  18261. tex->shader_prop = tex->material_prop = mat_tex.prop_name;
  18262. num_textures_in_material++;
  18263. }
  18264. }
  18265. }
  18266. ufbxi_check(ufbxi_resolve_file_content(uc));
  18267. ufbxi_for_ptr_list(ufbx_texture, p_texture, uc->scene.textures) {
  18268. ufbx_texture *texture = *p_texture;
  18269. ufbxi_texture_extra *extra = (ufbxi_texture_extra*)ufbxi_get_element_extra(uc, texture->element.element_id);
  18270. ufbx_prop *uv_set = ufbxi_find_prop(&texture->props, ufbxi_UVSet);
  18271. if (uv_set) {
  18272. texture->uv_set = uv_set->value_str;
  18273. } else {
  18274. texture->uv_set = ufbx_empty_string;
  18275. }
  18276. texture->video = (ufbx_video*)ufbxi_fetch_dst_element(&texture->element, false, NULL, UFBX_ELEMENT_VIDEO);
  18277. if (texture->video) {
  18278. texture->content = texture->video->content;
  18279. }
  18280. ufbxi_check(ufbxi_finalize_shader_texture(uc, texture));
  18281. ufbxi_check(ufbxi_resolve_filenames(uc, (ufbxi_strblob*)&texture->filename, (ufbxi_strblob*)&texture->absolute_filename, (ufbxi_strblob*)&texture->relative_filename, false));
  18282. ufbxi_check(ufbxi_resolve_filenames(uc, (ufbxi_strblob*)&texture->raw_filename, (ufbxi_strblob*)&texture->raw_absolute_filename, (ufbxi_strblob*)&texture->raw_relative_filename, true));
  18283. // Fetch layered texture layers and patch alphas/blend modes
  18284. if (texture->type == UFBX_TEXTURE_LAYERED) {
  18285. ufbxi_check(ufbxi_fetch_texture_layers(uc, &texture->layers, &texture->element));
  18286. if (extra) {
  18287. for (size_t i = 0, num = ufbxi_min_sz(extra->num_alphas, texture->layers.count); i < num; i++) {
  18288. texture->layers.data[i].alpha = extra->alphas[i];
  18289. }
  18290. for (size_t i = 0, num = ufbxi_min_sz(extra->num_blend_modes, texture->layers.count); i < num; i++) {
  18291. int32_t mode = extra->blend_modes[i];
  18292. if (mode >= 0 && mode < UFBX_BLEND_OVERLAY) {
  18293. texture->layers.data[i].blend_mode = (ufbx_blend_mode)mode;
  18294. }
  18295. }
  18296. }
  18297. }
  18298. ufbxi_check(ufbxi_insert_texture_file(uc, texture));
  18299. }
  18300. ufbxi_propagate_main_textures(&uc->scene);
  18301. ufbxi_check(ufbxi_pop_texture_files(uc));
  18302. // Second pass to fetch material maps
  18303. ufbxi_for_ptr_list(ufbx_material, p_material, uc->scene.materials) {
  18304. ufbx_material *material = *p_material;
  18305. ufbxi_check(ufbxi_sort_material_textures(uc, material->textures.data, material->textures.count));
  18306. ufbxi_fetch_maps(&uc->scene, material);
  18307. // Fetch `ufbx_material_texture.shader_prop` names
  18308. if (material->shader) {
  18309. ufbxi_for_ptr_list(ufbx_shader_binding, p_binding, material->shader->bindings) {
  18310. ufbx_shader_binding *binding = *p_binding;
  18311. ufbxi_for_list(ufbx_shader_prop_binding, prop, binding->prop_bindings) {
  18312. ufbx_string name = prop->material_prop;
  18313. size_t index = SIZE_MAX;
  18314. ufbxi_macro_lower_bound_eq(ufbx_material_texture, 4, &index, material->textures.data, 0, material->textures.count,
  18315. ( ufbxi_str_less(a->material_prop, name) ), ( a->material_prop.data == name.data ));
  18316. for (; index < material->textures.count && material->textures.data[index].shader_prop.data == name.data; index++) {
  18317. material->textures.data[index].shader_prop = prop->shader_prop;
  18318. }
  18319. }
  18320. }
  18321. }
  18322. }
  18323. ufbxi_for_ptr_list(ufbx_display_layer, p_layer, uc->scene.display_layers) {
  18324. ufbx_display_layer *layer = *p_layer;
  18325. ufbxi_check(ufbxi_fetch_dst_elements(uc, &layer->nodes, &layer->element, false, true, NULL, UFBX_ELEMENT_NODE));
  18326. }
  18327. ufbxi_for_ptr_list(ufbx_selection_set, p_set, uc->scene.selection_sets) {
  18328. ufbx_selection_set *set = *p_set;
  18329. ufbxi_check(ufbxi_fetch_dst_elements(uc, &set->nodes, &set->element, false, true, NULL, UFBX_ELEMENT_SELECTION_NODE));
  18330. }
  18331. ufbxi_for_ptr_list(ufbx_selection_node, p_node, uc->scene.selection_nodes) {
  18332. ufbx_selection_node *node = *p_node;
  18333. node->target_node = (ufbx_node*)ufbxi_fetch_dst_element(&node->element, false, NULL, UFBX_ELEMENT_NODE);
  18334. node->target_mesh = (ufbx_mesh*)ufbxi_fetch_dst_element(&node->element, false, NULL, UFBX_ELEMENT_MESH);
  18335. if (!node->target_mesh && node->target_node) {
  18336. node->target_mesh = node->target_node->mesh;
  18337. } else if (!node->target_node && node->target_mesh && node->target_mesh->instances.count > 0) {
  18338. node->target_node = node->target_mesh->instances.data[0];
  18339. }
  18340. ufbx_mesh *mesh = node->target_mesh;
  18341. if (mesh) {
  18342. ufbxi_check(ufbxi_validate_indices(uc, &node->vertices, mesh->num_vertices));
  18343. ufbxi_check(ufbxi_validate_indices(uc, &node->edges, mesh->num_edges));
  18344. ufbxi_check(ufbxi_validate_indices(uc, &node->faces, mesh->num_faces));
  18345. }
  18346. }
  18347. ufbxi_for_ptr_list(ufbx_constraint, p_constraint, uc->scene.constraints) {
  18348. ufbx_constraint *constraint = *p_constraint;
  18349. size_t tmp_base = uc->tmp_stack.num_items;
  18350. // Find property connections in _both_ src and dst connections as they are inconsistent
  18351. // in pre-7000 files. For example "Constrained Object" is a "PO" connection in 6100.
  18352. ufbxi_for_list(ufbx_connection, conn, constraint->element.connections_src) {
  18353. if (conn->src_prop.length == 0 || conn->dst->type != UFBX_ELEMENT_NODE) continue;
  18354. ufbxi_check(ufbxi_add_constraint_prop(uc, constraint, (ufbx_node*)conn->dst, conn->src_prop.data));
  18355. }
  18356. ufbxi_for_list(ufbx_connection, conn, constraint->element.connections_dst) {
  18357. if (conn->dst_prop.length == 0 || conn->src->type != UFBX_ELEMENT_NODE) continue;
  18358. ufbxi_check(ufbxi_add_constraint_prop(uc, constraint, (ufbx_node*)conn->src, conn->dst_prop.data));
  18359. }
  18360. size_t num_targets = uc->tmp_stack.num_items - tmp_base;
  18361. constraint->targets.count = num_targets;
  18362. constraint->targets.data = ufbxi_push_pop(&uc->result, &uc->tmp_stack, ufbx_constraint_target, num_targets);
  18363. ufbxi_check(constraint->targets.data);
  18364. }
  18365. ufbxi_for_ptr_list(ufbx_audio_layer, p_layer, uc->scene.audio_layers) {
  18366. ufbx_audio_layer *layer = *p_layer;
  18367. ufbxi_check(ufbxi_fetch_dst_elements(uc, &layer->clips, &layer->element, false, true, NULL, UFBX_ELEMENT_AUDIO_CLIP));
  18368. }
  18369. ufbxi_for_ptr_list(ufbx_lod_group, p_lod, uc->scene.lod_groups) {
  18370. ufbxi_check(ufbxi_finalize_lod_group(uc, *p_lod));
  18371. }
  18372. ufbxi_check(ufbxi_fetch_file_textures(uc));
  18373. // NOTE: This will be patched over in `ufbxi_update_scene()` if there are `anim_layers`
  18374. if (uc->scene.anim_layers.count == 0) {
  18375. ufbxi_check(ufbxi_push_anim(uc, &uc->scene.anim, NULL, 0));
  18376. }
  18377. uc->scene.metadata.ktime_second = uc->ktime_sec;
  18378. // Maya seems to use scale of 100/3, Blender binary uses exactly 33, ASCII has always value of 1.0
  18379. if (uc->version < 6000) {
  18380. uc->scene.metadata.bone_prop_size_unit = 1.0f;
  18381. } else if (uc->exporter == UFBX_EXPORTER_BLENDER_BINARY) {
  18382. uc->scene.metadata.bone_prop_size_unit = 33.0f;
  18383. } else if (uc->exporter == UFBX_EXPORTER_BLENDER_ASCII) {
  18384. uc->scene.metadata.bone_prop_size_unit = 1.0f;
  18385. } else {
  18386. uc->scene.metadata.bone_prop_size_unit = (ufbx_real)(100.0/3.0);
  18387. }
  18388. if (uc->exporter == UFBX_EXPORTER_BLENDER_ASCII) {
  18389. uc->scene.metadata.bone_prop_limb_length_relative = false;
  18390. } else {
  18391. uc->scene.metadata.bone_prop_limb_length_relative = true;
  18392. }
  18393. return 1;
  18394. }
  18395. // -- Interpret the read scene
  18396. static ufbxi_forceinline void ufbxi_add_translate(ufbx_transform *t, ufbx_vec3 v)
  18397. {
  18398. t->translation.x += v.x;
  18399. t->translation.y += v.y;
  18400. t->translation.z += v.z;
  18401. }
  18402. static ufbxi_forceinline void ufbxi_sub_translate(ufbx_transform *t, ufbx_vec3 v)
  18403. {
  18404. t->translation.x -= v.x;
  18405. t->translation.y -= v.y;
  18406. t->translation.z -= v.z;
  18407. }
  18408. static ufbxi_forceinline void ufbxi_mul_scale(ufbx_transform *t, ufbx_vec3 v)
  18409. {
  18410. t->translation.x *= v.x;
  18411. t->translation.y *= v.y;
  18412. t->translation.z *= v.z;
  18413. t->scale.x *= v.x;
  18414. t->scale.y *= v.y;
  18415. t->scale.z *= v.z;
  18416. }
  18417. static ufbxi_forceinline void ufbxi_mul_scale_real(ufbx_transform *t, ufbx_real v)
  18418. {
  18419. t->translation.x *= v;
  18420. t->translation.y *= v;
  18421. t->translation.z *= v;
  18422. t->scale.x *= v;
  18423. t->scale.y *= v;
  18424. t->scale.z *= v;
  18425. }
  18426. static ufbxi_noinline ufbx_quat ufbxi_mul_quat(ufbx_quat a, ufbx_quat b)
  18427. {
  18428. ufbx_quat r;
  18429. r.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y;
  18430. r.y = a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x;
  18431. r.z = a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w;
  18432. r.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z;
  18433. return r;
  18434. }
  18435. static ufbxi_forceinline void ufbxi_add_weighted_vec3(ufbx_vec3 *r, ufbx_vec3 b, ufbx_real w)
  18436. {
  18437. r->x += b.x * w;
  18438. r->y += b.y * w;
  18439. r->z += b.z * w;
  18440. }
  18441. static ufbxi_forceinline void ufbxi_add_weighted_quat(ufbx_quat *r, ufbx_quat b, ufbx_real w)
  18442. {
  18443. r->x += b.x * w;
  18444. r->y += b.y * w;
  18445. r->z += b.z * w;
  18446. r->w += b.w * w;
  18447. }
  18448. static ufbxi_noinline void ufbxi_add_weighted_mat(ufbx_matrix *r, const ufbx_matrix *b, ufbx_real w)
  18449. {
  18450. ufbxi_add_weighted_vec3(&r->cols[0], b->cols[0], w);
  18451. ufbxi_add_weighted_vec3(&r->cols[1], b->cols[1], w);
  18452. ufbxi_add_weighted_vec3(&r->cols[2], b->cols[2], w);
  18453. ufbxi_add_weighted_vec3(&r->cols[3], b->cols[3], w);
  18454. }
  18455. static void ufbxi_mul_rotate(ufbx_transform *t, ufbx_vec3 v, ufbx_rotation_order order)
  18456. {
  18457. if (ufbxi_is_vec3_zero(v)) return;
  18458. ufbx_quat q = ufbx_euler_to_quat(v, order);
  18459. if (t->rotation.w != 1.0) {
  18460. t->rotation = ufbxi_mul_quat(q, t->rotation);
  18461. } else {
  18462. t->rotation = q;
  18463. }
  18464. if (!ufbxi_is_vec3_zero(t->translation)) {
  18465. t->translation = ufbx_quat_rotate_vec3(q, t->translation);
  18466. }
  18467. }
  18468. static void ufbxi_mul_rotate_quat(ufbx_transform *t, ufbx_quat q)
  18469. {
  18470. if (ufbxi_is_quat_identity(q)) return;
  18471. if (t->rotation.w != 1.0) {
  18472. t->rotation = ufbxi_mul_quat(q, t->rotation);
  18473. } else {
  18474. t->rotation = q;
  18475. }
  18476. if (!ufbxi_is_vec3_zero(t->translation)) {
  18477. t->translation = ufbx_quat_rotate_vec3(q, t->translation);
  18478. }
  18479. }
  18480. static void ufbxi_mul_inv_rotate(ufbx_transform *t, ufbx_vec3 v, ufbx_rotation_order order)
  18481. {
  18482. if (ufbxi_is_vec3_zero(v)) return;
  18483. ufbx_quat q = ufbx_euler_to_quat(v, order);
  18484. q.x = -q.x; q.y = -q.y; q.z = -q.z;
  18485. if (t->rotation.w != 1.0) {
  18486. t->rotation = ufbxi_mul_quat(q, t->rotation);
  18487. } else {
  18488. t->rotation = q;
  18489. }
  18490. if (!ufbxi_is_vec3_zero(t->translation)) {
  18491. t->translation = ufbx_quat_rotate_vec3(q, t->translation);
  18492. }
  18493. }
  18494. // -- Updating state from properties
  18495. ufbxi_forceinline static void ufbxi_mirror_translation(ufbx_vec3 *p_vec, ufbx_mirror_axis axis)
  18496. {
  18497. ufbxi_dev_assert(axis);
  18498. p_vec->v[axis - 1] = -p_vec->v[axis - 1];
  18499. }
  18500. ufbxi_forceinline static void ufbxi_mirror_rotation(ufbx_quat *p_quat, ufbx_mirror_axis axis)
  18501. {
  18502. ufbxi_dev_assert(axis);
  18503. p_quat->v[axis % 3] = -p_quat->v[axis % 3];
  18504. p_quat->v[(axis + 1) % 3] = -p_quat->v[(axis + 1) % 3];
  18505. }
  18506. ufbxi_noinline static ufbx_transform ufbxi_get_geometry_transform(const ufbx_props *props, ufbx_node *node)
  18507. {
  18508. ufbx_vec3 translation = ufbxi_find_vec3(props, ufbxi_GeometricTranslation, 0.0f, 0.0f, 0.0f);
  18509. ufbx_vec3 rotation = ufbxi_find_vec3(props, ufbxi_GeometricRotation, 0.0f, 0.0f, 0.0f);
  18510. ufbx_vec3 scaling = ufbxi_find_vec3(props, ufbxi_GeometricScaling, 1.0f, 1.0f, 1.0f);
  18511. ufbx_transform t = { { 0,0,0 }, { 0,0,0,1 }, { 1,1,1 }};
  18512. // WorldTransform = ParentWorldTransform * T * R * S * (OT * OR * OS)
  18513. ufbxi_mul_scale(&t, scaling);
  18514. ufbxi_mul_rotate(&t, rotation, UFBX_ROTATION_ORDER_XYZ);
  18515. ufbxi_add_translate(&t, translation);
  18516. if (node->has_adjust_transform) {
  18517. t.translation.x *= node->adjust_translation_scale;
  18518. t.translation.y *= node->adjust_translation_scale;
  18519. t.translation.z *= node->adjust_translation_scale;
  18520. }
  18521. if (node->adjust_mirror_axis) {
  18522. ufbxi_mirror_translation(&t.translation, node->adjust_mirror_axis);
  18523. ufbxi_mirror_rotation(&t.rotation, node->adjust_mirror_axis);
  18524. }
  18525. return t;
  18526. }
  18527. ufbxi_noinline static ufbx_transform ufbxi_get_transform(const ufbx_props *props, ufbx_rotation_order order, const ufbx_node *node, const ufbx_vec3 *translation_scale)
  18528. {
  18529. ufbx_vec3 scale_pivot = ufbxi_find_vec3(props, ufbxi_ScalingPivot, 0.0f, 0.0f, 0.0f);
  18530. ufbx_vec3 rot_pivot = ufbxi_find_vec3(props, ufbxi_RotationPivot, 0.0f, 0.0f, 0.0f);
  18531. ufbx_vec3 scale_offset = ufbxi_find_vec3(props, ufbxi_ScalingOffset, 0.0f, 0.0f, 0.0f);
  18532. ufbx_vec3 rot_offset = ufbxi_find_vec3(props, ufbxi_RotationOffset, 0.0f, 0.0f, 0.0f);
  18533. ufbx_vec3 translation = ufbxi_find_vec3(props, ufbxi_Lcl_Translation, 0.0f, 0.0f, 0.0f);
  18534. ufbx_vec3 rotation = ufbxi_find_vec3(props, ufbxi_Lcl_Rotation, 0.0f, 0.0f, 0.0f);
  18535. ufbx_vec3 scaling = ufbxi_find_vec3(props, ufbxi_Lcl_Scaling, 1.0f, 1.0f, 1.0f);
  18536. ufbx_vec3 pre_rotation = ufbxi_find_vec3(props, ufbxi_PreRotation, 0.0f, 0.0f, 0.0f);
  18537. ufbx_vec3 post_rotation = ufbxi_find_vec3(props, ufbxi_PostRotation, 0.0f, 0.0f, 0.0f);
  18538. ufbx_transform t = { { 0,0,0 }, { 0,0,0,1 }, { 1,1,1 }};
  18539. // WorldTransform = ParentWorldTransform * T * Roff * Rp * Rpre * R * Rpost * Rp-1 * Soff * Sp * S * Sp-1
  18540. // NOTE: Rpost is inverted (!) after converting from PostRotation Euler angles
  18541. if (translation_scale) {
  18542. translation.x *= translation_scale->x;
  18543. translation.y *= translation_scale->y;
  18544. translation.z *= translation_scale->z;
  18545. }
  18546. if (node->has_adjust_transform) {
  18547. ufbxi_mul_rotate_quat(&t, node->adjust_post_rotation);
  18548. ufbxi_mul_scale_real(&t, node->adjust_post_scale);
  18549. }
  18550. ufbxi_sub_translate(&t, scale_pivot);
  18551. ufbxi_mul_scale(&t, scaling);
  18552. ufbxi_add_translate(&t, scale_pivot);
  18553. ufbxi_add_translate(&t, scale_offset);
  18554. ufbxi_sub_translate(&t, rot_pivot);
  18555. ufbxi_mul_inv_rotate(&t, post_rotation, UFBX_ROTATION_ORDER_XYZ);
  18556. ufbxi_mul_rotate(&t, rotation, order);
  18557. ufbxi_mul_rotate(&t, pre_rotation, UFBX_ROTATION_ORDER_XYZ);
  18558. ufbxi_add_translate(&t, rot_pivot);
  18559. ufbxi_add_translate(&t, rot_offset);
  18560. ufbxi_add_translate(&t, translation);
  18561. if (node->has_adjust_transform) {
  18562. ufbxi_add_translate(&t, node->adjust_pre_translation);
  18563. ufbxi_mul_rotate_quat(&t, node->adjust_pre_rotation);
  18564. ufbxi_mul_scale_real(&t, node->adjust_pre_scale);
  18565. t.translation.x *= node->adjust_translation_scale;
  18566. t.translation.y *= node->adjust_translation_scale;
  18567. t.translation.z *= node->adjust_translation_scale;
  18568. }
  18569. if (node->adjust_mirror_axis) {
  18570. ufbxi_mirror_translation(&t.translation, node->adjust_mirror_axis);
  18571. ufbxi_mirror_rotation(&t.rotation, node->adjust_mirror_axis);
  18572. }
  18573. return t;
  18574. }
  18575. ufbxi_noinline static ufbx_quat ufbxi_get_rotation(const ufbx_props *props, ufbx_rotation_order order, const ufbx_node *node)
  18576. {
  18577. ufbx_vec3 rotation = ufbxi_find_vec3(props, ufbxi_Lcl_Rotation, 0.0f, 0.0f, 0.0f);
  18578. ufbx_vec3 pre_rotation = ufbxi_find_vec3(props, ufbxi_PreRotation, 0.0f, 0.0f, 0.0f);
  18579. ufbx_vec3 post_rotation = ufbxi_find_vec3(props, ufbxi_PostRotation, 0.0f, 0.0f, 0.0f);
  18580. ufbx_transform t = { { 0,0,0 }, { 0,0,0,1 }, { 1,1,1 }};
  18581. if (node->has_adjust_transform) {
  18582. ufbxi_mul_rotate_quat(&t, node->adjust_post_rotation);
  18583. }
  18584. ufbxi_mul_inv_rotate(&t, post_rotation, UFBX_ROTATION_ORDER_XYZ);
  18585. ufbxi_mul_rotate(&t, rotation, order);
  18586. ufbxi_mul_rotate(&t, pre_rotation, UFBX_ROTATION_ORDER_XYZ);
  18587. if (node->has_adjust_transform) {
  18588. ufbxi_mul_rotate_quat(&t, node->adjust_pre_rotation);
  18589. }
  18590. return t.rotation;
  18591. }
  18592. ufbxi_noinline static ufbx_vec3 ufbxi_get_scale(const ufbx_props *props, const ufbx_node *node)
  18593. {
  18594. ufbx_vec3 scaling = ufbxi_find_vec3(props, ufbxi_Lcl_Scaling, 1.0f, 1.0f, 1.0f);
  18595. ufbx_transform t = { { 0,0,0 }, { 0,0,0,1 }, { 1,1,1 }};
  18596. if (node->has_adjust_transform) {
  18597. ufbxi_mul_scale_real(&t, node->adjust_post_scale);
  18598. }
  18599. ufbxi_mul_scale(&t, scaling);
  18600. if (node->has_adjust_transform) {
  18601. ufbxi_mul_scale_real(&t, node->adjust_pre_scale);
  18602. }
  18603. return t.scale;
  18604. }
  18605. ufbxi_noinline static ufbx_transform ufbxi_get_texture_transform(const ufbx_props *props)
  18606. {
  18607. ufbx_vec3 scale_pivot = ufbxi_find_vec3(props, ufbxi_TextureScalingPivot, 0.0f, 0.0f, 0.0f);
  18608. ufbx_vec3 rot_pivot = ufbxi_find_vec3(props, ufbxi_TextureRotationPivot, 0.0f, 0.0f, 0.0f);
  18609. ufbx_vec3 translation = ufbxi_find_vec3(props, ufbxi_Translation, 0.0f, 0.0f, 0.0f);
  18610. ufbx_vec3 rotation = ufbxi_find_vec3(props, ufbxi_Rotation, 0.0f, 0.0f, 0.0f);
  18611. ufbx_vec3 scaling = ufbxi_find_vec3(props, ufbxi_Scaling, 1.0f, 1.0f, 1.0f);
  18612. ufbx_transform t = { { 0,0,0 }, { 0,0,0,1 }, { 1,1,1 }};
  18613. ufbxi_sub_translate(&t, scale_pivot);
  18614. ufbxi_mul_scale(&t, scaling);
  18615. ufbxi_add_translate(&t, scale_pivot);
  18616. ufbxi_sub_translate(&t, rot_pivot);
  18617. ufbxi_mul_rotate(&t, rotation, UFBX_ROTATION_ORDER_XYZ);
  18618. ufbxi_add_translate(&t, rot_pivot);
  18619. ufbxi_add_translate(&t, translation);
  18620. if (ufbxi_find_int(props, ufbxi_UVSwap, 0) != 0) {
  18621. const ufbx_vec3 swap_scale = { -1.0f, 0.0f, 0.0f };
  18622. const ufbx_vec3 swap_rotate = { 0.0f, 0.0f, -90.0f };
  18623. ufbxi_mul_scale(&t, swap_scale);
  18624. ufbxi_mul_rotate(&t, swap_rotate, UFBX_ROTATION_ORDER_XYZ);
  18625. }
  18626. return t;
  18627. }
  18628. ufbxi_noinline static ufbx_transform ufbxi_get_constraint_transform(const ufbx_props *props)
  18629. {
  18630. ufbx_vec3 translation = ufbxi_find_vec3(props, ufbxi_Translation, 0.0f, 0.0f, 0.0f);
  18631. ufbx_vec3 rotation = ufbxi_find_vec3(props, ufbxi_Rotation, 0.0f, 0.0f, 0.0f);
  18632. ufbx_vec3 rotation_offset = ufbxi_find_vec3(props, ufbxi_RotationOffset, 0.0f, 0.0f, 0.0f);
  18633. ufbx_vec3 scaling = ufbxi_find_vec3(props, ufbxi_Scaling, 1.0f, 1.0f, 1.0f);
  18634. ufbx_transform t = { { 0,0,0 }, { 0,0,0,1 }, { 1,1,1 }};
  18635. ufbxi_mul_scale(&t, scaling);
  18636. ufbxi_mul_rotate(&t, rotation, UFBX_ROTATION_ORDER_XYZ);
  18637. ufbxi_mul_rotate(&t, rotation_offset, UFBX_ROTATION_ORDER_XYZ);
  18638. ufbxi_add_translate(&t, translation);
  18639. return t;
  18640. }
  18641. ufbxi_noinline static void ufbxi_update_node(ufbx_node *node, const ufbx_transform_override *overrides, size_t num_overrides)
  18642. {
  18643. node->rotation_order = (ufbx_rotation_order)ufbxi_find_enum(&node->props, ufbxi_RotationOrder, UFBX_ROTATION_ORDER_XYZ, UFBX_ROTATION_ORDER_SPHERIC);
  18644. node->euler_rotation = ufbxi_find_vec3(&node->props, ufbxi_Lcl_Rotation, 0.0f, 0.0f, 0.0f);
  18645. if (!node->is_root) {
  18646. const ufbx_vec3 *transform_scale = NULL;
  18647. if (node->parent && node->parent->scale_helper) {
  18648. transform_scale = &node->parent->scale_helper->local_transform.scale;
  18649. }
  18650. node->local_transform = ufbxi_get_transform(&node->props, node->rotation_order, node, transform_scale);
  18651. if (node->is_scale_helper && node->parent && node->parent->inherit_scale_node) {
  18652. ufbx_node *scale_parent = node->parent->inherit_scale_node;
  18653. if (scale_parent->scale_helper) {
  18654. ufbx_vec3 inherit_scale = scale_parent->scale_helper->local_transform.scale;
  18655. node->local_transform.scale.x *= inherit_scale.x;
  18656. node->local_transform.scale.y *= inherit_scale.y;
  18657. node->local_transform.scale.z *= inherit_scale.z;
  18658. }
  18659. }
  18660. if (num_overrides > 0) {
  18661. uint32_t typed_id = node->typed_id;
  18662. size_t override_ix = SIZE_MAX;
  18663. ufbxi_macro_lower_bound_eq(ufbx_transform_override, 16, &override_ix, overrides, 0, num_overrides,
  18664. ( a->node_id < typed_id ), ( a->node_id == typed_id ));
  18665. if (override_ix != SIZE_MAX) {
  18666. node->local_transform = overrides[override_ix].transform;
  18667. }
  18668. }
  18669. node->node_to_parent = ufbx_transform_to_matrix(&node->local_transform);
  18670. node->geometry_transform = ufbxi_get_geometry_transform(&node->props, node);
  18671. } else {
  18672. node->geometry_transform = ufbx_identity_transform;
  18673. }
  18674. ufbx_matrix unscaled_node_to_parent = ufbxi_unscaled_transform_to_matrix(&node->local_transform);
  18675. node->inherit_scale = node->local_transform.scale;
  18676. ufbx_node *parent = node->parent;
  18677. if (parent) {
  18678. if (node->inherit_mode == UFBX_INHERIT_MODE_NORMAL) {
  18679. node->node_to_world = ufbx_matrix_mul(&parent->node_to_world, &node->node_to_parent);
  18680. node->unscaled_node_to_world = ufbx_matrix_mul(&parent->node_to_world, &unscaled_node_to_parent);
  18681. } else {
  18682. ufbx_transform transform = node->local_transform;
  18683. ufbx_vec3 parent_scale = ufbxi_one_vec3;
  18684. if (node->inherit_scale_node) {
  18685. parent_scale = node->inherit_scale_node->inherit_scale;
  18686. }
  18687. transform.scale.x *= parent_scale.x;
  18688. transform.scale.y *= parent_scale.y;
  18689. transform.scale.z *= parent_scale.z;
  18690. transform.translation.x *= parent->inherit_scale.x;
  18691. transform.translation.y *= parent->inherit_scale.y;
  18692. transform.translation.z *= parent->inherit_scale.z;
  18693. ufbx_matrix node_to_unscaled_parent = ufbx_transform_to_matrix(&transform);
  18694. ufbx_matrix unscaled_node_to_unscaled_parent = ufbxi_unscaled_transform_to_matrix(&transform);
  18695. node->inherit_scale = transform.scale;
  18696. node->node_to_world = ufbx_matrix_mul(&parent->unscaled_node_to_world, &node_to_unscaled_parent);
  18697. node->unscaled_node_to_world = ufbx_matrix_mul(&parent->unscaled_node_to_world, &unscaled_node_to_unscaled_parent);
  18698. }
  18699. } else {
  18700. node->node_to_world = node->node_to_parent;
  18701. node->unscaled_node_to_world = unscaled_node_to_parent;
  18702. }
  18703. if (!ufbxi_is_transform_identity(&node->geometry_transform)) {
  18704. node->geometry_to_node = ufbx_transform_to_matrix(&node->geometry_transform);
  18705. node->geometry_to_world = ufbx_matrix_mul(&node->node_to_world, &node->geometry_to_node);
  18706. node->has_geometry_transform = true;
  18707. } else {
  18708. node->geometry_to_node = ufbx_identity_matrix;
  18709. node->geometry_to_world = node->node_to_world;
  18710. node->has_geometry_transform = false;
  18711. }
  18712. node->visible = ufbxi_find_int(&node->props, ufbxi_Visibility, 1) != 0;
  18713. }
  18714. ufbxi_noinline static void ufbxi_update_light(ufbx_light *light)
  18715. {
  18716. // NOTE: FBX seems to store intensities 100x of what's specified in at least
  18717. // Maya and Blender, should there be a quirks mode to not do this for specific
  18718. // exporters. Does the FBX SDK do this transparently as well?
  18719. light->intensity = ufbxi_find_real(&light->props, ufbxi_Intensity, (ufbx_real)100.0) / (ufbx_real)100.0;
  18720. light->color = ufbxi_find_vec3(&light->props, ufbxi_Color, 1.0f, 1.0f, 1.0f);
  18721. light->type = (ufbx_light_type)ufbxi_find_enum(&light->props, ufbxi_LightType, 0, UFBX_LIGHT_VOLUME);
  18722. light->decay = (ufbx_light_decay)ufbxi_find_enum(&light->props, ufbxi_DecayType, UFBX_LIGHT_DECAY_NONE, UFBX_LIGHT_DECAY_CUBIC);
  18723. light->area_shape = (ufbx_light_area_shape)ufbxi_find_enum(&light->props, ufbxi_AreaLightShape, 0, UFBX_LIGHT_AREA_SHAPE_SPHERE);
  18724. light->inner_angle = ufbxi_find_real(&light->props, ufbxi_HotSpot, 0.0f);
  18725. light->inner_angle = ufbxi_find_real(&light->props, ufbxi_InnerAngle, light->inner_angle);
  18726. light->outer_angle = ufbxi_find_real(&light->props, ufbxi_Cone_angle, 0.0f);
  18727. light->outer_angle = ufbxi_find_real(&light->props, ufbxi_ConeAngle, light->outer_angle);
  18728. light->outer_angle = ufbxi_find_real(&light->props, ufbxi_OuterAngle, light->outer_angle);
  18729. light->cast_light = ufbxi_find_int(&light->props, ufbxi_CastLight, 1) != 0;
  18730. light->cast_shadows = ufbxi_find_int(&light->props, ufbxi_CastShadows, 0) != 0;
  18731. }
  18732. typedef struct {
  18733. // 1/1000 decimal fixed point for size
  18734. uint16_t film_size_x, film_size_y;
  18735. } ufbxi_aperture_format;
  18736. static const ufbxi_aperture_format ufbxi_aperture_formats[] = {
  18737. { 1000, 1000, }, // UFBX_APERTURE_FORMAT_CUSTOM
  18738. { 404, 295, }, // UFBX_APERTURE_FORMAT_16MM_THEATRICAL
  18739. { 493, 292, }, // UFBX_APERTURE_FORMAT_SUPER_16MM
  18740. { 864, 630, }, // UFBX_APERTURE_FORMAT_35MM_ACADEMY
  18741. { 816, 612, }, // UFBX_APERTURE_FORMAT_35MM_TV_PROJECTION
  18742. { 980, 735, }, // UFBX_APERTURE_FORMAT_35MM_FULL_APERTURE
  18743. { 825, 446, }, // UFBX_APERTURE_FORMAT_35MM_185_PROJECTION
  18744. { 864, 732, }, // UFBX_APERTURE_FORMAT_35MM_ANAMORPHIC
  18745. { 2066, 906, }, // UFBX_APERTURE_FORMAT_70MM_PROJECTION
  18746. { 1485, 991, }, // UFBX_APERTURE_FORMAT_VISTAVISION
  18747. { 2080, 1480, }, // UFBX_APERTURE_FORMAT_DYNAVISION
  18748. { 2772, 2072, }, // UFBX_APERTURE_FORMAT_IMAX
  18749. };
  18750. ufbxi_noinline static void ufbxi_update_camera(ufbx_scene *scene, ufbx_camera *camera)
  18751. {
  18752. camera->projection_mode = (ufbx_projection_mode)ufbxi_find_enum(&camera->props, ufbxi_CameraProjectionType, 0, UFBX_PROJECTION_MODE_ORTHOGRAPHIC);
  18753. camera->aspect_mode = (ufbx_aspect_mode)ufbxi_find_enum(&camera->props, ufbxi_AspectRatioMode, 0, UFBX_ASPECT_MODE_FIXED_HEIGHT);
  18754. camera->aperture_mode = (ufbx_aperture_mode)ufbxi_find_enum(&camera->props, ufbxi_ApertureMode, UFBX_APERTURE_MODE_VERTICAL, UFBX_APERTURE_MODE_FOCAL_LENGTH);
  18755. camera->aperture_format = (ufbx_aperture_format)ufbxi_find_enum(&camera->props, ufbxi_ApertureFormat, UFBX_APERTURE_FORMAT_CUSTOM, UFBX_APERTURE_FORMAT_IMAX);
  18756. camera->gate_fit = (ufbx_gate_fit)ufbxi_find_enum(&camera->props, ufbxi_GateFit, 0, UFBX_GATE_FIT_STRETCH);
  18757. camera->near_plane = ufbxi_find_real(&camera->props, ufbxi_NearPlane, 0.0f);
  18758. camera->far_plane = ufbxi_find_real(&camera->props, ufbxi_FarPlane, 0.0f);
  18759. // Search both W/H and Width/Height but prefer the latter
  18760. ufbx_real aspect_x = ufbxi_find_real(&camera->props, ufbxi_AspectW, 0.0f);
  18761. ufbx_real aspect_y = ufbxi_find_real(&camera->props, ufbxi_AspectH, 0.0f);
  18762. aspect_x = ufbxi_find_real(&camera->props, ufbxi_AspectWidth, aspect_x);
  18763. aspect_y = ufbxi_find_real(&camera->props, ufbxi_AspectHeight, aspect_y);
  18764. ufbx_real fov = ufbxi_find_real(&camera->props, ufbxi_FieldOfView, 0.0f);
  18765. ufbx_real fov_x = ufbxi_find_real(&camera->props, ufbxi_FieldOfViewX, 0.0f);
  18766. ufbx_real fov_y = ufbxi_find_real(&camera->props, ufbxi_FieldOfViewY, 0.0f);
  18767. ufbx_real focal_length = ufbxi_find_real(&camera->props, ufbxi_FocalLength, 0.0f);
  18768. ufbx_real ortho_extent = scene->metadata.ortho_size_unit * ufbxi_find_real(&camera->props, ufbxi_OrthoZoom, 1.0f);
  18769. ufbxi_aperture_format format = ufbxi_aperture_formats[camera->aperture_format];
  18770. ufbx_vec2 film_size = { (ufbx_real)format.film_size_x * (ufbx_real)0.001, (ufbx_real)format.film_size_y * (ufbx_real)0.001 };
  18771. ufbx_real squeeze_ratio = camera->aperture_format == UFBX_APERTURE_FORMAT_35MM_ANAMORPHIC ? 2.0f : 1.0f;
  18772. film_size.x = ufbxi_find_real(&camera->props, ufbxi_FilmWidth, film_size.x);
  18773. film_size.y = ufbxi_find_real(&camera->props, ufbxi_FilmHeight, film_size.y);
  18774. squeeze_ratio = ufbxi_find_real(&camera->props, ufbxi_FilmSqueezeRatio, squeeze_ratio);
  18775. if (aspect_x <= 0.0f && aspect_y <= 0.0f) {
  18776. aspect_x = film_size.x > 0.0f ? film_size.x : 1.0f;
  18777. aspect_y = film_size.y > 0.0f ? film_size.y : 1.0f;
  18778. } else if (aspect_x <= 0.0f) {
  18779. if (film_size.x > 0.0f && film_size.y > 0.0f) {
  18780. aspect_x = aspect_y / film_size.y * film_size.x;
  18781. } else {
  18782. aspect_x = aspect_y;
  18783. }
  18784. } else if (aspect_y <= 0.0f) {
  18785. if (film_size.x > 0.0f && film_size.y > 0.0f) {
  18786. aspect_y = aspect_x / film_size.x * film_size.y;
  18787. } else {
  18788. aspect_y = aspect_x;
  18789. }
  18790. }
  18791. film_size.y *= squeeze_ratio;
  18792. // TODO: Should this be done always?
  18793. ortho_extent *= scene->metadata.geometry_scale;
  18794. camera->near_plane *= scene->metadata.geometry_scale;
  18795. camera->far_plane *= scene->metadata.geometry_scale;
  18796. camera->focal_length_mm = focal_length;
  18797. camera->film_size_inch = film_size;
  18798. camera->squeeze_ratio = squeeze_ratio;
  18799. camera->orthographic_extent = ortho_extent;
  18800. switch (camera->aspect_mode) {
  18801. case UFBX_ASPECT_MODE_WINDOW_SIZE:
  18802. case UFBX_ASPECT_MODE_FIXED_RATIO:
  18803. camera->resolution_is_pixels = false;
  18804. camera->resolution.x = aspect_x;
  18805. camera->resolution.y = aspect_y;
  18806. break;
  18807. case UFBX_ASPECT_MODE_FIXED_RESOLUTION:
  18808. camera->resolution_is_pixels = true;
  18809. camera->resolution.x = aspect_x;
  18810. camera->resolution.y = aspect_y;
  18811. break;
  18812. case UFBX_ASPECT_MODE_FIXED_WIDTH:
  18813. camera->resolution_is_pixels = true;
  18814. camera->resolution.x = aspect_x;
  18815. camera->resolution.y = aspect_x * aspect_y;
  18816. break;
  18817. case UFBX_ASPECT_MODE_FIXED_HEIGHT:
  18818. camera->resolution_is_pixels = true;
  18819. camera->resolution.x = aspect_y * aspect_x;
  18820. camera->resolution.y = aspect_y;
  18821. break;
  18822. default:
  18823. ufbxi_unreachable("Unexpected aspect mode");
  18824. }
  18825. ufbx_real aspect_ratio = camera->resolution.x / camera->resolution.y;
  18826. ufbx_real film_ratio = film_size.x / film_size.y;
  18827. camera->aspect_ratio = aspect_ratio;
  18828. ufbx_gate_fit effective_fit = camera->gate_fit;
  18829. if (effective_fit == UFBX_GATE_FIT_FILL) {
  18830. effective_fit = aspect_ratio > film_ratio ? UFBX_GATE_FIT_HORIZONTAL : UFBX_GATE_FIT_VERTICAL;
  18831. } else if (effective_fit == UFBX_GATE_FIT_OVERSCAN) {
  18832. effective_fit = aspect_ratio < film_ratio ? UFBX_GATE_FIT_HORIZONTAL : UFBX_GATE_FIT_VERTICAL;
  18833. }
  18834. switch (effective_fit) {
  18835. case UFBX_GATE_FIT_NONE:
  18836. camera->aperture_size_inch = camera->film_size_inch;
  18837. camera->orthographic_size.x = ortho_extent;
  18838. camera->orthographic_size.y = ortho_extent;
  18839. break;
  18840. case UFBX_GATE_FIT_VERTICAL:
  18841. camera->aperture_size_inch.x = camera->film_size_inch.y * aspect_ratio;
  18842. camera->aperture_size_inch.y = camera->film_size_inch.y;
  18843. camera->orthographic_size.x = ortho_extent * aspect_ratio;
  18844. camera->orthographic_size.y = ortho_extent;
  18845. break;
  18846. case UFBX_GATE_FIT_HORIZONTAL:
  18847. camera->aperture_size_inch.x = camera->film_size_inch.x;
  18848. camera->aperture_size_inch.y = camera->film_size_inch.x / aspect_ratio;
  18849. camera->orthographic_size.x = ortho_extent;
  18850. camera->orthographic_size.y = ortho_extent / aspect_ratio;
  18851. break;
  18852. case UFBX_GATE_FIT_FILL:
  18853. case UFBX_GATE_FIT_OVERSCAN:
  18854. camera->aperture_size_inch = camera->film_size_inch;
  18855. camera->orthographic_size.x = ortho_extent;
  18856. camera->orthographic_size.y = ortho_extent;
  18857. ufbxi_unreachable("Unreachable, set to vertical/horizontal above");
  18858. break;
  18859. case UFBX_GATE_FIT_STRETCH:
  18860. camera->aperture_size_inch = camera->film_size_inch;
  18861. camera->orthographic_size.x = ortho_extent;
  18862. camera->orthographic_size.y = ortho_extent;
  18863. // TODO: Not sure what to do here...
  18864. break;
  18865. default:
  18866. ufbxi_unreachable("Unexpected gate fit");
  18867. }
  18868. switch (camera->aperture_mode) {
  18869. case UFBX_APERTURE_MODE_HORIZONTAL_AND_VERTICAL:
  18870. camera->field_of_view_deg.x = fov_x;
  18871. camera->field_of_view_deg.y = fov_y;
  18872. camera->field_of_view_tan.x = (ufbx_real)ufbx_tan((double)(fov_x * (UFBXI_DEG_TO_RAD * 0.5f)));
  18873. camera->field_of_view_tan.y = (ufbx_real)ufbx_tan((double)(fov_y * (UFBXI_DEG_TO_RAD * 0.5f)));
  18874. break;
  18875. case UFBX_APERTURE_MODE_HORIZONTAL:
  18876. camera->field_of_view_deg.x = fov;
  18877. camera->field_of_view_tan.x = (ufbx_real)ufbx_tan((double)(fov * (UFBXI_DEG_TO_RAD * 0.5f)));
  18878. camera->field_of_view_tan.y = camera->field_of_view_tan.x / aspect_ratio;
  18879. camera->field_of_view_deg.y = (ufbx_real)ufbx_atan((double)camera->field_of_view_tan.y) * UFBXI_RAD_TO_DEG * 2.0f;
  18880. break;
  18881. case UFBX_APERTURE_MODE_VERTICAL:
  18882. camera->field_of_view_deg.y = fov;
  18883. camera->field_of_view_tan.y = (ufbx_real)ufbx_tan((double)(fov * (UFBXI_DEG_TO_RAD * 0.5f)));
  18884. camera->field_of_view_tan.x = camera->field_of_view_tan.y * aspect_ratio;
  18885. camera->field_of_view_deg.x = (ufbx_real)ufbx_atan((double)camera->field_of_view_tan.x) * UFBXI_RAD_TO_DEG * 2.0f;
  18886. break;
  18887. case UFBX_APERTURE_MODE_FOCAL_LENGTH:
  18888. camera->field_of_view_tan.x = camera->aperture_size_inch.x / (camera->focal_length_mm * UFBXI_MM_TO_INCH) * 0.5f;
  18889. camera->field_of_view_tan.y = camera->aperture_size_inch.y / (camera->focal_length_mm * UFBXI_MM_TO_INCH) * 0.5f;
  18890. camera->field_of_view_deg.x = (ufbx_real)ufbx_atan((double)camera->field_of_view_tan.x) * UFBXI_RAD_TO_DEG * 2.0f;
  18891. camera->field_of_view_deg.y = (ufbx_real)ufbx_atan((double)camera->field_of_view_tan.y) * UFBXI_RAD_TO_DEG * 2.0f;
  18892. break;
  18893. default:
  18894. ufbxi_unreachable("Unexpected aperture mode");
  18895. }
  18896. if (camera->projection_mode == UFBX_PROJECTION_MODE_PERSPECTIVE) {
  18897. camera->projection_plane = camera->field_of_view_tan;
  18898. } else {
  18899. camera->projection_plane = camera->orthographic_size;
  18900. }
  18901. }
  18902. ufbxi_noinline static void ufbxi_update_bone(ufbx_scene *scene, ufbx_bone *bone)
  18903. {
  18904. ufbx_real unit = scene->metadata.bone_prop_size_unit;
  18905. bone->radius = ufbxi_find_real(&bone->props, ufbxi_Size, unit) / unit;
  18906. if (scene->metadata.bone_prop_limb_length_relative) {
  18907. bone->relative_length = ufbxi_find_real(&bone->props, ufbxi_LimbLength, 1.0f);
  18908. } else {
  18909. bone->relative_length = 1.0f;
  18910. }
  18911. }
  18912. ufbxi_noinline static void ufbxi_update_line_curve(ufbx_line_curve *line)
  18913. {
  18914. line->color = ufbxi_find_vec3(&line->props, ufbxi_Color, 1.0f, 1.0f, 1.0f);
  18915. }
  18916. ufbxi_noinline static void ufbxi_update_pose(ufbx_pose *pose)
  18917. {
  18918. ufbxi_for_list(ufbx_bone_pose, bone, pose->bone_poses) {
  18919. ufbx_node *node = bone->bone_node;
  18920. const ufbx_matrix *parent_to_world = &ufbx_identity_matrix;
  18921. ufbx_bone_pose *bone_pose = ufbx_get_bone_pose(pose, node->parent);
  18922. if (bone_pose) {
  18923. parent_to_world = &bone_pose->bone_to_world;
  18924. } else if (node->parent) {
  18925. parent_to_world = &node->parent->node_to_world;
  18926. }
  18927. ufbx_matrix world_to_parent = ufbx_matrix_invert(parent_to_world);
  18928. bone->bone_to_parent = ufbx_matrix_mul(&world_to_parent, &bone->bone_to_world);
  18929. }
  18930. }
  18931. ufbxi_noinline static void ufbxi_update_skin_cluster(ufbx_skin_cluster *cluster)
  18932. {
  18933. if (cluster->bone_node) {
  18934. cluster->geometry_to_world = ufbx_matrix_mul(&cluster->bone_node->node_to_world, &cluster->geometry_to_bone);
  18935. } else {
  18936. cluster->geometry_to_world = ufbx_matrix_mul(&cluster->bind_to_world, &cluster->geometry_to_bone);
  18937. }
  18938. cluster->geometry_to_world_transform = ufbx_matrix_to_transform(&cluster->geometry_to_world);
  18939. }
  18940. ufbxi_noinline static void ufbxi_update_blend_channel(ufbx_blend_channel *channel)
  18941. {
  18942. ufbx_real weight = ufbxi_find_real(&channel->props, ufbxi_DeformPercent, 0.0f) * (ufbx_real)0.01;
  18943. channel->weight = weight;
  18944. ptrdiff_t num_keys = (ptrdiff_t)channel->keyframes.count;
  18945. if (num_keys > 0) {
  18946. ufbx_blend_keyframe *keys = channel->keyframes.data;
  18947. // Reset the effective weights to zero and find the split around zero
  18948. ptrdiff_t last_negative = -1;
  18949. for (ptrdiff_t i = 0; i < num_keys; i++) {
  18950. keys[i].effective_weight = (ufbx_real)0.0;
  18951. if (keys[i].target_weight < 0.0) last_negative = i;
  18952. }
  18953. // Find either the next or last keyframe away from zero
  18954. ufbx_blend_keyframe zero_key = { NULL };
  18955. ufbx_blend_keyframe *prev = &zero_key, *next = &zero_key;
  18956. if (weight > 0.0) {
  18957. if (last_negative >= 0) prev = &keys[last_negative];
  18958. for (ptrdiff_t i = last_negative + 1; i < num_keys; i++) {
  18959. prev = next;
  18960. next = &keys[i];
  18961. if (next->target_weight > weight) break;
  18962. }
  18963. } else {
  18964. if (last_negative + 1 < num_keys) prev = &keys[last_negative + 1];
  18965. for (ptrdiff_t i = last_negative; i >= 0; i--) {
  18966. prev = next;
  18967. next = &keys[i];
  18968. if (next->target_weight < weight) break;
  18969. }
  18970. }
  18971. // Linearly interpolate between the endpoints with the weight
  18972. ufbx_real delta = next->target_weight - prev->target_weight;
  18973. if (delta != 0.0) {
  18974. ufbx_real t = (weight - prev->target_weight) / delta;
  18975. prev->effective_weight = 1.0f - t;
  18976. next->effective_weight = t;
  18977. }
  18978. }
  18979. }
  18980. ufbxi_noinline static void ufbxi_update_material(ufbx_scene *scene, ufbx_material *material)
  18981. {
  18982. if (material->props.num_animated > 0) {
  18983. ufbxi_fetch_maps(scene, material);
  18984. }
  18985. }
  18986. ufbxi_noinline static void ufbxi_update_texture(ufbx_texture *texture)
  18987. {
  18988. texture->uv_transform = ufbxi_get_texture_transform(&texture->props);
  18989. if (!ufbxi_is_transform_identity(&texture->uv_transform)) {
  18990. texture->has_uv_transform = true;
  18991. texture->texture_to_uv = ufbx_transform_to_matrix(&texture->uv_transform);
  18992. texture->uv_to_texture = ufbx_matrix_invert(&texture->texture_to_uv);
  18993. } else {
  18994. texture->has_uv_transform = false;
  18995. texture->texture_to_uv = ufbx_identity_matrix;
  18996. texture->uv_to_texture = ufbx_identity_matrix;
  18997. }
  18998. texture->wrap_u = (ufbx_wrap_mode)ufbxi_find_enum(&texture->props, ufbxi_WrapModeU, 0, UFBX_WRAP_CLAMP);
  18999. texture->wrap_v = (ufbx_wrap_mode)ufbxi_find_enum(&texture->props, ufbxi_WrapModeV, 0, UFBX_WRAP_CLAMP);
  19000. if (texture->shader) {
  19001. ufbxi_update_shader_texture(texture, texture->shader);
  19002. }
  19003. }
  19004. ufbxi_noinline static void ufbxi_update_anim_stack(ufbx_scene *scene, ufbx_anim_stack *stack)
  19005. {
  19006. ufbx_prop *begin, *end;
  19007. begin = ufbxi_find_prop(&stack->props, ufbxi_LocalStart);
  19008. end = ufbxi_find_prop(&stack->props, ufbxi_LocalStop);
  19009. if (!begin || !end) {
  19010. begin = ufbxi_find_prop(&stack->props, ufbxi_ReferenceStart);
  19011. end = ufbxi_find_prop(&stack->props, ufbxi_ReferenceStop);
  19012. }
  19013. if (begin && end) {
  19014. stack->time_begin = (double)begin->value_int / (double)scene->metadata.ktime_second;
  19015. stack->time_end = (double)end->value_int / (double)scene->metadata.ktime_second;
  19016. }
  19017. stack->anim->time_begin = stack->time_begin;
  19018. stack->anim->time_end = stack->time_end;
  19019. }
  19020. ufbxi_noinline static void ufbxi_update_display_layer(ufbx_display_layer *layer)
  19021. {
  19022. layer->visible = ufbxi_find_int(&layer->props, ufbxi_Show, 1) != 0;
  19023. layer->frozen = ufbxi_find_int(&layer->props, ufbxi_Freeze, 1) != 0;
  19024. layer->ui_color = ufbxi_find_vec3(&layer->props, ufbxi_Color, 0.8f, 0.8f, 0.8f);
  19025. }
  19026. ufbxi_noinline static void ufbxi_find_bool3(bool *dst, ufbx_props *props, const char *name, bool default_value)
  19027. {
  19028. size_t name_len = strlen(name);
  19029. char local[64];
  19030. ufbx_assert(name_len < sizeof(local) - 2);
  19031. memcpy(local, name, name_len);
  19032. size_t local_len = name_len + 1;
  19033. local[local_len] = '\0';
  19034. int64_t def = default_value ? 1 : 0;
  19035. local[name_len] = 'X';
  19036. dst[0] = ufbx_find_int_len(props, local, local_len, def) != 0;
  19037. local[name_len] = 'Y';
  19038. dst[1] = ufbx_find_int_len(props, local, local_len, def) != 0;
  19039. local[name_len] = 'Z';
  19040. dst[2] = ufbx_find_int_len(props, local, local_len, def) != 0;
  19041. }
  19042. ufbxi_noinline static void ufbxi_update_constraint(ufbx_constraint *constraint)
  19043. {
  19044. ufbx_props *props = &constraint->props;
  19045. ufbx_constraint_type constraint_type = constraint->type;
  19046. constraint->transform_offset = ufbxi_get_constraint_transform(props);
  19047. constraint->weight = ufbxi_find_real(props, ufbxi_Weight, (ufbx_real)100.0) / (ufbx_real)100.0;
  19048. ufbxi_for_list(ufbx_constraint_target, target, constraint->targets) {
  19049. ufbx_node *node = target->node;
  19050. ufbx_real weight_scale = (ufbx_real)100.0;
  19051. if (constraint_type == UFBX_CONSTRAINT_SINGLE_CHAIN_IK) {
  19052. // IK weights seem to be not scaled 100x?
  19053. weight_scale = (ufbx_real)1.0;
  19054. }
  19055. ufbx_prop *prop; // ufbxi_uninit
  19056. ufbx_string parts[2]; // ufbxi_uninit
  19057. parts[0] = node->name;
  19058. parts[1] = ufbxi_str_c(".Weight");
  19059. prop = ufbx_find_prop_concat(props, parts, 2);
  19060. target->weight = (prop ? prop->value_real : weight_scale) / weight_scale;
  19061. if (constraint_type == UFBX_CONSTRAINT_PARENT) {
  19062. parts[1] = ufbxi_str_c(".Offset T");
  19063. prop = ufbx_find_prop_concat(props, parts, 2);
  19064. ufbx_vec3 t = prop ? prop->value_vec3 : ufbx_zero_vec3;
  19065. parts[1] = ufbxi_str_c(".Offset R");
  19066. prop = ufbx_find_prop_concat(props, parts, 2);
  19067. ufbx_vec3 r = prop ? prop->value_vec3 : ufbx_zero_vec3;
  19068. parts[1] = ufbxi_str_c(".Offset S");
  19069. prop = ufbx_find_prop_concat(props, parts, 2);
  19070. ufbx_vec3 s = prop ? prop->value_vec3 : ufbxi_one_vec3;
  19071. target->transform.translation = t;
  19072. target->transform.rotation = ufbx_euler_to_quat(r, UFBX_ROTATION_ORDER_XYZ);
  19073. target->transform.scale = s;
  19074. }
  19075. }
  19076. constraint->active = ufbx_find_int(props, "Active", 1) != 0;
  19077. if (constraint_type == UFBX_CONSTRAINT_AIM) {
  19078. ufbxi_find_bool3(constraint->constrain_rotation, props, "Affect", 1);
  19079. const ufbx_vec3 default_aim = { 1.0f, 0.0f, 0.0f };
  19080. const ufbx_vec3 default_up = { 0.0f, 1.0f, 0.0f };
  19081. int64_t up_type = ufbx_find_int(props, "WorldUpType", 0);
  19082. if (up_type >= 0 && up_type < UFBX_CONSTRAINT_AIM_UP_NONE) {
  19083. constraint->aim_up_type = (ufbx_constraint_aim_up_type)up_type;
  19084. }
  19085. constraint->aim_vector = ufbx_find_vec3(props, "AimVector", default_aim);
  19086. constraint->aim_up_vector = ufbx_find_vec3(props, "UpVector", default_up);
  19087. } else if (constraint_type == UFBX_CONSTRAINT_PARENT) {
  19088. ufbxi_find_bool3(constraint->constrain_translation, props, "AffectTranslation", 1);
  19089. ufbxi_find_bool3(constraint->constrain_rotation, props, "AffectRotation", 1);
  19090. ufbxi_find_bool3(constraint->constrain_scale, props, "AffectScale", 0);
  19091. } else if (constraint_type == UFBX_CONSTRAINT_POSITION) {
  19092. ufbxi_find_bool3(constraint->constrain_translation, props, "Affect", 1);
  19093. } else if (constraint_type == UFBX_CONSTRAINT_ROTATION) {
  19094. ufbxi_find_bool3(constraint->constrain_rotation, props, "Affect", 1);
  19095. } else if (constraint_type == UFBX_CONSTRAINT_SCALE) {
  19096. ufbxi_find_bool3(constraint->constrain_scale, props, "Affect", 1);
  19097. } else if (constraint_type == UFBX_CONSTRAINT_SINGLE_CHAIN_IK) {
  19098. constraint->constrain_rotation[0] = true;
  19099. constraint->constrain_rotation[1] = true;
  19100. constraint->constrain_rotation[2] = true;
  19101. constraint->ik_pole_vector = ufbx_find_vec3(props, "PoleVectorType", ufbx_zero_vec3);
  19102. }
  19103. }
  19104. ufbxi_noinline static void ufbxi_update_anim(ufbx_scene *scene)
  19105. {
  19106. if (scene->anim_stacks.count > 0) {
  19107. scene->anim = scene->anim_stacks.data[0]->anim;
  19108. }
  19109. }
  19110. static ufbxi_forceinline void ufbxi_mirror_matrix_dst(ufbx_matrix *m, ufbx_mirror_axis axis)
  19111. {
  19112. if (axis == 0) return;
  19113. int32_t ax = (int32_t)axis - 1;
  19114. m->cols[0].v[ax] = -m->cols[0].v[ax];
  19115. m->cols[1].v[ax] = -m->cols[1].v[ax];
  19116. m->cols[2].v[ax] = -m->cols[2].v[ax];
  19117. m->cols[3].v[ax] = -m->cols[3].v[ax];
  19118. }
  19119. static ufbxi_forceinline void ufbxi_mirror_matrix_src(ufbx_matrix *m, ufbx_mirror_axis axis)
  19120. {
  19121. if (axis == 0) return;
  19122. int32_t ax = (int32_t)axis - 1;
  19123. m->cols[ax].x = -m->cols[ax].x;
  19124. m->cols[ax].y = -m->cols[ax].y;
  19125. m->cols[ax].z = -m->cols[ax].z;
  19126. }
  19127. static ufbxi_noinline void ufbxi_mirror_matrix(ufbx_matrix *m, ufbx_mirror_axis axis)
  19128. {
  19129. if (axis == 0) return;
  19130. ufbxi_mirror_matrix_src(m, axis);
  19131. ufbxi_mirror_matrix_dst(m, axis);
  19132. }
  19133. ufbxi_noinline static void ufbxi_update_initial_clusters(ufbx_scene *scene)
  19134. {
  19135. ufbxi_for_ptr_list(ufbx_skin_cluster, p_cluster, scene->skin_clusters) {
  19136. ufbx_skin_cluster *cluster = *p_cluster;
  19137. cluster->geometry_to_bone = cluster->mesh_node_to_bone;
  19138. }
  19139. ufbx_mirror_axis mirror_axis = scene->metadata.mirror_axis;
  19140. ufbx_real geometry_scale = scene->metadata.geometry_scale;
  19141. // Space conversion for bind matrices
  19142. {
  19143. ufbx_matrix world_to_units;
  19144. ufbx_real translation_scale = 1.0f;
  19145. if (scene->metadata.space_conversion == UFBX_SPACE_CONVERSION_TRANSFORM_ROOT && scene->metadata.mirror_axis == UFBX_MIRROR_AXIS_NONE) {
  19146. world_to_units = scene->root_node->node_to_parent;
  19147. } else {
  19148. ufbx_transform root_transform;
  19149. root_transform.translation = ufbx_zero_vec3;
  19150. root_transform.rotation = scene->metadata.root_rotation;
  19151. root_transform.scale.x = scene->metadata.root_scale;
  19152. root_transform.scale.y = scene->metadata.root_scale;
  19153. root_transform.scale.z = scene->metadata.root_scale;
  19154. world_to_units = ufbx_transform_to_matrix(&root_transform);
  19155. translation_scale = scene->metadata.geometry_scale;
  19156. }
  19157. ufbxi_for_ptr_list(ufbx_skin_cluster, p_cluster, scene->skin_clusters) {
  19158. ufbx_skin_cluster *cluster = *p_cluster;
  19159. cluster->bind_to_world = ufbx_matrix_mul(&world_to_units, &cluster->bind_to_world);
  19160. cluster->bind_to_world.cols[3].x *= translation_scale;
  19161. cluster->bind_to_world.cols[3].y *= translation_scale;
  19162. cluster->bind_to_world.cols[3].z *= translation_scale;
  19163. ufbxi_mirror_matrix(&cluster->bind_to_world, mirror_axis);
  19164. }
  19165. ufbxi_for_ptr_list(ufbx_pose, p_pose, scene->poses) {
  19166. ufbxi_for_list(ufbx_bone_pose, pose, (*p_pose)->bone_poses) {
  19167. pose->bone_to_world = ufbx_matrix_mul(&world_to_units, &pose->bone_to_world);
  19168. pose->bone_to_world.cols[3].x *= translation_scale;
  19169. pose->bone_to_world.cols[3].y *= translation_scale;
  19170. pose->bone_to_world.cols[3].z *= translation_scale;
  19171. ufbxi_mirror_matrix(&pose->bone_to_world, mirror_axis);
  19172. }
  19173. }
  19174. }
  19175. // Patch initial `mesh_node_to_bone`
  19176. ufbxi_for_ptr_list(ufbx_skin_cluster, p_cluster, scene->skin_clusters) {
  19177. ufbx_skin_cluster *cluster = *p_cluster;
  19178. ufbx_skin_deformer *skin = (ufbx_skin_deformer*)ufbxi_fetch_src_element(&cluster->element, false, NULL, UFBX_ELEMENT_SKIN_DEFORMER);
  19179. if (!skin) continue;
  19180. ufbx_node *node = (ufbx_node*)ufbxi_fetch_src_element(&skin->element, false, NULL, UFBX_ELEMENT_NODE);
  19181. if (!node) {
  19182. ufbx_mesh *mesh = (ufbx_mesh*)ufbxi_fetch_src_element(&skin->element, false, NULL, UFBX_ELEMENT_MESH);
  19183. if (mesh && mesh->instances.count > 0) {
  19184. node = mesh->instances.data[0];
  19185. }
  19186. }
  19187. if (!node) continue;
  19188. // Normalize to the non-helper node
  19189. if (node->is_geometry_transform_helper) {
  19190. node = node->parent;
  19191. }
  19192. if (ufbxi_matrix_all_zero(&cluster->mesh_node_to_bone)) {
  19193. // If `mesh_node_to_bone` is not explicitly specified compute it from bind pose.
  19194. ufbx_matrix world_to_bind = ufbx_matrix_invert(&cluster->bind_to_world);
  19195. cluster->mesh_node_to_bone = ufbx_matrix_mul(&world_to_bind, &node->node_to_world);
  19196. } else {
  19197. // If `mesh_node_to_bone` is explicit, we may need to modify it for space conversion.
  19198. ufbxi_mirror_matrix(&cluster->mesh_node_to_bone, mirror_axis);
  19199. if (geometry_scale != 1.0f) {
  19200. cluster->mesh_node_to_bone.cols[3].x *= geometry_scale;
  19201. cluster->mesh_node_to_bone.cols[3].y *= geometry_scale;
  19202. cluster->mesh_node_to_bone.cols[3].z *= geometry_scale;
  19203. }
  19204. }
  19205. // HACK: Account for geometry transforms by looking at the transform of the
  19206. // helper node if one is present. I don't think this is exactly how the skinning
  19207. // matrices are formed.
  19208. // TODO: Add a test with moving the skinned mesh root around.
  19209. if (node->geometry_transform_helper) {
  19210. ufbx_node *geo_node = node->geometry_transform_helper;
  19211. cluster->geometry_to_bone = ufbx_matrix_mul(&cluster->mesh_node_to_bone, &geo_node->node_to_parent);
  19212. } else if (node->has_geometry_transform) {
  19213. cluster->geometry_to_bone = ufbx_matrix_mul(&cluster->mesh_node_to_bone, &node->geometry_to_node);
  19214. } else {
  19215. cluster->geometry_to_bone = cluster->mesh_node_to_bone;
  19216. }
  19217. }
  19218. }
  19219. ufbxi_noinline static ufbx_coordinate_axis ufbxi_find_axis(const ufbx_props *props, const char *axis_name, const char *sign_name)
  19220. {
  19221. int64_t axis = ufbxi_find_int(props, axis_name, 3);
  19222. int64_t sign = ufbxi_find_int(props, sign_name, 2);
  19223. switch (axis) {
  19224. case 0: return sign > 0 ? UFBX_COORDINATE_AXIS_POSITIVE_X : UFBX_COORDINATE_AXIS_NEGATIVE_X;
  19225. case 1: return sign > 0 ? UFBX_COORDINATE_AXIS_POSITIVE_Y : UFBX_COORDINATE_AXIS_NEGATIVE_Y;
  19226. case 2: return sign > 0 ? UFBX_COORDINATE_AXIS_POSITIVE_Z : UFBX_COORDINATE_AXIS_NEGATIVE_Z;
  19227. default: return UFBX_COORDINATE_AXIS_UNKNOWN;
  19228. }
  19229. }
  19230. static const ufbx_real ufbxi_time_mode_fps[] = {
  19231. 30.0f, // UFBX_TIME_MODE_DEFAULT
  19232. 120.0f, // UFBX_TIME_MODE_120_FPS
  19233. 100.0f, // UFBX_TIME_MODE_100_FPS
  19234. 60.0f, // UFBX_TIME_MODE_60_FPS
  19235. 50.0f, // UFBX_TIME_MODE_50_FPS
  19236. 48.0f, // UFBX_TIME_MODE_48_FPS
  19237. 30.0f, // UFBX_TIME_MODE_30_FPS
  19238. 30.0f, // UFBX_TIME_MODE_30_FPS_DROP
  19239. 29.97f, // UFBX_TIME_MODE_NTSC_DROP_FRAME
  19240. 29.97f, // UFBX_TIME_MODE_NTSC_FULL_FRAME
  19241. 25.0f, // UFBX_TIME_MODE_PAL
  19242. 24.0f, // UFBX_TIME_MODE_24_FPS
  19243. 1000.0f, // UFBX_TIME_MODE_1000_FPS
  19244. 23.976f, // UFBX_TIME_MODE_FILM_FULL_FRAME
  19245. 24.0f, // UFBX_TIME_MODE_CUSTOM
  19246. 96.0f, // UFBX_TIME_MODE_96_FPS
  19247. 72.0f, // UFBX_TIME_MODE_72_FPS
  19248. 59.94f, // UFBX_TIME_MODE_59_94_FPS
  19249. };
  19250. // Returns whether a non-identity matrix was needed
  19251. static ufbxi_noinline bool ufbxi_axis_matrix(ufbx_matrix *mat, ufbx_coordinate_axes src, ufbx_coordinate_axes dst)
  19252. {
  19253. uint32_t src_x = (uint32_t)src.right;
  19254. uint32_t dst_x = (uint32_t)dst.right;
  19255. uint32_t src_y = (uint32_t)src.up;
  19256. uint32_t dst_y = (uint32_t)dst.up;
  19257. uint32_t src_z = (uint32_t)src.front;
  19258. uint32_t dst_z = (uint32_t)dst.front;
  19259. if (src_x == dst_x && src_y == dst_y && src_z == dst_z) return false;
  19260. // Remap axes (axis enum divided by 2) potentially flipping if the signs (enum parity) doesn't match
  19261. memset(mat, 0, sizeof(ufbx_matrix));
  19262. mat->cols[src_x >> 1].v[dst_x >> 1] = ((src_x ^ dst_x) & 1) == 0 ? 1.0f : -1.0f;
  19263. mat->cols[src_y >> 1].v[dst_y >> 1] = ((src_y ^ dst_y) & 1) == 0 ? 1.0f : -1.0f;
  19264. mat->cols[src_z >> 1].v[dst_z >> 1] = ((src_z ^ dst_z) & 1) == 0 ? 1.0f : -1.0f;
  19265. return true;
  19266. }
  19267. ufbxi_noinline static void ufbxi_update_adjust_transforms(ufbxi_context *uc, ufbx_scene *scene)
  19268. {
  19269. ufbx_transform root_transform = ufbx_identity_transform;
  19270. if (!ufbxi_matrix_all_zero(&uc->axis_matrix)) {
  19271. root_transform = ufbx_matrix_to_transform(&uc->axis_matrix);
  19272. }
  19273. root_transform.scale.x *= uc->unit_scale;
  19274. root_transform.scale.y *= uc->unit_scale;
  19275. root_transform.scale.z *= uc->unit_scale;
  19276. ufbx_space_conversion conversion = uc->opts.space_conversion;
  19277. ufbx_quat light_post_rotation = ufbx_identity_quat;
  19278. ufbx_quat camera_post_rotation = ufbx_identity_quat;
  19279. ufbx_vec3 light_direction = { 0.0f, -1.0f, 0.0f };
  19280. bool has_light_transform = false;
  19281. bool has_camera_transform = false;
  19282. if (ufbx_coordinate_axes_valid(uc->opts.target_light_axes)) {
  19283. ufbx_matrix mat; // ufbxi_uninit
  19284. ufbx_coordinate_axes light_axes = {
  19285. UFBX_COORDINATE_AXIS_POSITIVE_X,
  19286. UFBX_COORDINATE_AXIS_NEGATIVE_Z,
  19287. UFBX_COORDINATE_AXIS_POSITIVE_Y,
  19288. };
  19289. if (ufbxi_axis_matrix(&mat, uc->opts.target_light_axes, light_axes)) {
  19290. light_post_rotation = ufbx_matrix_to_transform(&mat).rotation;
  19291. ufbx_matrix inv = ufbx_matrix_invert(&mat);
  19292. light_direction = ufbx_transform_direction(&inv, light_direction);
  19293. has_light_transform = true;
  19294. }
  19295. }
  19296. if (ufbx_coordinate_axes_valid(uc->opts.target_camera_axes)) {
  19297. ufbx_matrix mat; // ufbxi_uninit
  19298. ufbx_coordinate_axes camera_axes = {
  19299. UFBX_COORDINATE_AXIS_POSITIVE_Z,
  19300. UFBX_COORDINATE_AXIS_POSITIVE_Y,
  19301. UFBX_COORDINATE_AXIS_NEGATIVE_X,
  19302. };
  19303. if (ufbxi_axis_matrix(&mat, uc->opts.target_camera_axes, camera_axes)) {
  19304. camera_post_rotation = ufbx_matrix_to_transform(&mat).rotation;
  19305. has_camera_transform = true;
  19306. }
  19307. }
  19308. ufbxi_for_ptr_list(ufbx_light, p_light, scene->lights) {
  19309. ufbx_light *light = *p_light;
  19310. light->local_direction.x = 0.0f;
  19311. light->local_direction.y = -1.0f;
  19312. light->local_direction.z = 0.0f;
  19313. }
  19314. ufbx_real root_scale = ufbxi_min3(root_transform.scale);
  19315. scene->metadata.space_conversion = conversion;
  19316. if (conversion == UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY) {
  19317. scene->metadata.geometry_scale = root_scale;
  19318. scene->metadata.root_scale = 1.0f;
  19319. } else {
  19320. scene->metadata.geometry_scale = 1.0f;
  19321. scene->metadata.root_scale = root_scale;
  19322. }
  19323. scene->metadata.root_rotation = root_transform.rotation;
  19324. ufbxi_for_ptr_list(ufbx_node, p_node, scene->nodes) {
  19325. ufbx_node *node = *p_node;
  19326. node->adjust_post_rotation = ufbx_identity_quat;
  19327. node->adjust_pre_rotation = ufbx_identity_quat;
  19328. node->adjust_pre_scale = 1.0f;
  19329. node->adjust_post_scale = 1.0f;
  19330. node->adjust_translation_scale = 1.0f;
  19331. if (conversion == UFBX_SPACE_CONVERSION_ADJUST_TRANSFORMS) {
  19332. if (node->node_depth <= 1 && !node->is_root) {
  19333. node->adjust_pre_rotation = root_transform.rotation;
  19334. node->adjust_pre_scale = root_scale;
  19335. node->has_adjust_transform = true;
  19336. node->has_root_adjust_transform = true;
  19337. }
  19338. } else if (conversion == UFBX_SPACE_CONVERSION_MODIFY_GEOMETRY) {
  19339. if (!node->is_root) {
  19340. if (node->node_depth <= 1) {
  19341. node->adjust_pre_rotation = root_transform.rotation;
  19342. }
  19343. node->adjust_translation_scale = root_scale;
  19344. node->has_adjust_transform = true;
  19345. }
  19346. }
  19347. if (node->parent) {
  19348. // We are not inheriting local scale, so propagate root scale manually and
  19349. // apply scale compensation if necessary.
  19350. ufbx_node *parent = node->parent;
  19351. if (parent->has_root_adjust_transform && node->inherit_mode == UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE) {
  19352. node->adjust_post_scale *= root_scale;
  19353. node->has_adjust_transform = true;
  19354. node->has_root_adjust_transform = true;
  19355. }
  19356. if (parent->is_scale_compensate_parent && node->original_inherit_mode == UFBX_INHERIT_MODE_IGNORE_PARENT_SCALE) {
  19357. ufbx_vec3 scale = ufbxi_find_vec3(&parent->props, ufbxi_Lcl_Scaling, 1.0f, 1.0f, 1.0f);
  19358. ufbx_real size = scale.x;
  19359. if (ufbx_fabs(scale.y - 1.0f) < ufbx_fabs(size - 1.0f)) size = scale.y;
  19360. if (ufbx_fabs(scale.z - 1.0f) < ufbx_fabs(size - 1.0f)) size = scale.z;
  19361. node->adjust_post_scale *= 1.0f / size;
  19362. node->has_adjust_transform = true;
  19363. }
  19364. }
  19365. if (node->all_attribs.count == 1) {
  19366. if (has_light_transform && node->light) {
  19367. node->adjust_post_rotation = light_post_rotation;
  19368. node->light->local_direction = light_direction;
  19369. node->has_adjust_transform = true;
  19370. }
  19371. if (has_camera_transform && node->camera) {
  19372. node->adjust_post_rotation = camera_post_rotation;
  19373. node->camera->projection_axes = uc->opts.target_camera_axes;
  19374. node->has_adjust_transform = true;
  19375. }
  19376. }
  19377. }
  19378. }
  19379. ufbxi_noinline static void ufbxi_update_scene(ufbx_scene *scene, bool initial, const ufbx_transform_override *transform_overrides, size_t num_transform_overrides)
  19380. {
  19381. ufbxi_for_ptr_list(ufbx_node, p_node, scene->nodes) {
  19382. ufbxi_update_node(*p_node, transform_overrides, num_transform_overrides);
  19383. }
  19384. ufbxi_for_ptr_list(ufbx_light, p_light, scene->lights) {
  19385. ufbxi_update_light(*p_light);
  19386. }
  19387. ufbxi_for_ptr_list(ufbx_camera, p_camera, scene->cameras) {
  19388. ufbxi_update_camera(scene, *p_camera);
  19389. }
  19390. ufbxi_for_ptr_list(ufbx_bone, p_bone, scene->bones) {
  19391. ufbxi_update_bone(scene, *p_bone);
  19392. }
  19393. ufbxi_for_ptr_list(ufbx_line_curve, p_line, scene->line_curves) {
  19394. ufbxi_update_line_curve(*p_line);
  19395. }
  19396. if (initial) {
  19397. ufbxi_update_initial_clusters(scene);
  19398. ufbxi_for_ptr_list(ufbx_pose, p_pose, scene->poses) {
  19399. ufbxi_update_pose(*p_pose);
  19400. }
  19401. }
  19402. ufbxi_for_ptr_list(ufbx_skin_cluster, p_cluster, scene->skin_clusters) {
  19403. ufbxi_update_skin_cluster(*p_cluster);
  19404. }
  19405. ufbxi_for_ptr_list(ufbx_blend_channel, p_channel, scene->blend_channels) {
  19406. ufbxi_update_blend_channel(*p_channel);
  19407. }
  19408. ufbxi_for_ptr_list(ufbx_texture, p_texture, scene->textures) {
  19409. ufbxi_update_texture(*p_texture);
  19410. }
  19411. ufbxi_propagate_main_textures(scene);
  19412. ufbxi_for_ptr_list(ufbx_material, p_material, scene->materials) {
  19413. ufbxi_update_material(scene, *p_material);
  19414. }
  19415. ufbxi_for_ptr_list(ufbx_anim_stack, p_stack, scene->anim_stacks) {
  19416. ufbxi_update_anim_stack(scene, *p_stack);
  19417. }
  19418. ufbxi_for_ptr_list(ufbx_display_layer, p_layer, scene->display_layers) {
  19419. ufbxi_update_display_layer(*p_layer);
  19420. }
  19421. ufbxi_for_ptr_list(ufbx_constraint, p_constraint, scene->constraints) {
  19422. ufbxi_update_constraint(*p_constraint);
  19423. }
  19424. ufbxi_update_anim(scene);
  19425. }
  19426. static ufbxi_noinline void ufbxi_update_scene_metadata(ufbx_metadata *metadata)
  19427. {
  19428. ufbx_props *props = &metadata->scene_props;
  19429. metadata->original_application.vendor = ufbx_find_string(props, "Original|ApplicationVendor", ufbx_empty_string);
  19430. metadata->original_application.name = ufbx_find_string(props, "Original|ApplicationName", ufbx_empty_string);
  19431. metadata->original_application.version = ufbx_find_string(props, "Original|ApplicationVersion", ufbx_empty_string);
  19432. metadata->latest_application.vendor = ufbx_find_string(props, "LastSaved|ApplicationVendor", ufbx_empty_string);
  19433. metadata->latest_application.name = ufbx_find_string(props, "LastSaved|ApplicationName", ufbx_empty_string);
  19434. metadata->latest_application.version = ufbx_find_string(props, "LastSaved|ApplicationVersion", ufbx_empty_string);
  19435. }
  19436. static const ufbx_real ufbxi_pow10_targets[] = {
  19437. 0.0f,
  19438. (ufbx_real)1e-8, (ufbx_real)1e-7, (ufbx_real)1e-6, (ufbx_real)1e-5,
  19439. (ufbx_real)1e-4, (ufbx_real)1e-3, (ufbx_real)1e-2, (ufbx_real)1e-1,
  19440. (ufbx_real)1e+0, (ufbx_real)1e+1, (ufbx_real)1e+2, (ufbx_real)1e+3,
  19441. (ufbx_real)1e+4, (ufbx_real)1e+5, (ufbx_real)1e+6, (ufbx_real)1e+7,
  19442. (ufbx_real)1e+8, (ufbx_real)1e+9,
  19443. };
  19444. static ufbxi_noinline ufbx_real ufbxi_round_if_near(const ufbx_real *targets, size_t num_targets, ufbx_real value)
  19445. {
  19446. for (size_t i = 0; i < num_targets; i++) {
  19447. double target = targets[i];
  19448. double error = target * 9.5367431640625e-7;
  19449. if (error < 0.0) error = -error;
  19450. if (error < 7.52316384526264005e-37) error = 7.52316384526264005e-37;
  19451. if (value >= target - error && value <= target + error) {
  19452. return (ufbx_real)target;
  19453. }
  19454. }
  19455. return value;
  19456. }
  19457. static ufbxi_noinline void ufbxi_update_scene_settings(ufbx_scene_settings *settings)
  19458. {
  19459. ufbx_real unit_scale_factor = ufbxi_find_real(&settings->props, ufbxi_UnitScaleFactor, 1.0f);
  19460. ufbx_real original_unit_scale_factor = ufbxi_find_real(&settings->props, ufbxi_OriginalUnitScaleFactor, unit_scale_factor);
  19461. settings->axes.up = ufbxi_find_axis(&settings->props, ufbxi_UpAxis, ufbxi_UpAxisSign);
  19462. settings->axes.front = ufbxi_find_axis(&settings->props, ufbxi_FrontAxis, ufbxi_FrontAxisSign);
  19463. settings->axes.right = ufbxi_find_axis(&settings->props, ufbxi_CoordAxis, ufbxi_CoordAxisSign);
  19464. settings->unit_meters = ufbxi_round_if_near(ufbxi_pow10_targets, ufbxi_arraycount(ufbxi_pow10_targets), unit_scale_factor * (ufbx_real)0.01);
  19465. settings->original_unit_meters = ufbxi_round_if_near(ufbxi_pow10_targets, ufbxi_arraycount(ufbxi_pow10_targets), original_unit_scale_factor * (ufbx_real)0.01);
  19466. settings->frames_per_second = ufbxi_find_real(&settings->props, ufbxi_CustomFrameRate, 24.0f);
  19467. settings->ambient_color = ufbxi_find_vec3(&settings->props, ufbxi_AmbientColor, 0.0f, 0.0f, 0.0f);
  19468. settings->original_axis_up = ufbxi_find_axis(&settings->props, ufbxi_OriginalUpAxis, ufbxi_OriginalUpAxisSign);
  19469. ufbx_prop *default_camera = ufbxi_find_prop(&settings->props, ufbxi_DefaultCamera);
  19470. if (default_camera) {
  19471. settings->default_camera = default_camera->value_str;
  19472. } else {
  19473. settings->default_camera = ufbx_empty_string;
  19474. }
  19475. settings->time_mode = (ufbx_time_mode)ufbxi_find_enum(&settings->props, ufbxi_TimeMode, UFBX_TIME_MODE_24_FPS, UFBX_TIME_MODE_59_94_FPS);
  19476. settings->time_protocol = (ufbx_time_protocol)ufbxi_find_enum(&settings->props, ufbxi_TimeProtocol, UFBX_TIME_PROTOCOL_DEFAULT, UFBX_TIME_PROTOCOL_DEFAULT);
  19477. settings->snap_mode = (ufbx_snap_mode)ufbxi_find_enum(&settings->props, ufbxi_SnapOnFrameMode, UFBX_SNAP_MODE_NONE, UFBX_SNAP_MODE_SNAP_AND_PLAY);
  19478. if (settings->time_mode != UFBX_TIME_MODE_CUSTOM) {
  19479. settings->frames_per_second = ufbxi_time_mode_fps[settings->time_mode];
  19480. }
  19481. }
  19482. static ufbxi_noinline void ufbxi_update_scene_settings_obj(ufbxi_context *uc)
  19483. {
  19484. ufbx_scene_settings *settings = &uc->scene.settings;
  19485. settings->original_unit_meters = settings->unit_meters = uc->opts.obj_unit_meters;
  19486. if (ufbx_coordinate_axes_valid(uc->opts.obj_axes)) {
  19487. settings->axes = uc->opts.obj_axes;
  19488. } else {
  19489. settings->axes.right = UFBX_COORDINATE_AXIS_UNKNOWN;
  19490. settings->axes.up = UFBX_COORDINATE_AXIS_UNKNOWN;
  19491. settings->axes.front = UFBX_COORDINATE_AXIS_UNKNOWN;
  19492. }
  19493. }
  19494. // -- Geometry caches
  19495. #if UFBXI_FEATURE_GEOMETRY_CACHE
  19496. typedef struct {
  19497. ufbxi_refcount refcount;
  19498. ufbx_geometry_cache cache;
  19499. uint32_t magic;
  19500. bool owned_by_scene;
  19501. ufbxi_buf string_buf;
  19502. } ufbxi_geometry_cache_imp;
  19503. ufbx_static_assert(geometry_cache_imp_offset, offsetof(ufbxi_geometry_cache_imp, cache) == sizeof(ufbxi_refcount));
  19504. typedef struct {
  19505. ufbx_string name;
  19506. ufbx_string interpretation;
  19507. uint32_t sample_rate;
  19508. uint32_t start_time;
  19509. uint32_t end_time;
  19510. uint32_t current_time;
  19511. uint32_t consecutive_fails;
  19512. bool try_load;
  19513. } ufbxi_cache_tmp_channel;
  19514. typedef enum {
  19515. UFBXI_CACHE_XML_TYPE_NONE,
  19516. UFBXI_CACHE_XML_TYPE_FILE_PER_FRAME,
  19517. UFBXI_CACHE_XML_TYPE_SINGLE_FILE,
  19518. } ufbxi_cache_xml_type;
  19519. typedef enum {
  19520. UFBXI_CACHE_XML_FORMAT_NONE,
  19521. UFBXI_CACHE_XML_FORMAT_MCC,
  19522. UFBXI_CACHE_XML_FORMAT_MCX,
  19523. } ufbxi_cache_xml_format;
  19524. typedef struct {
  19525. ufbx_error error;
  19526. ufbx_string filename;
  19527. bool owned_by_scene;
  19528. bool ignore_if_not_found;
  19529. ufbx_geometry_cache_opts opts;
  19530. ufbxi_allocator *ator_tmp;
  19531. ufbxi_allocator ator_result;
  19532. ufbxi_buf result;
  19533. ufbxi_buf tmp;
  19534. ufbxi_buf tmp_stack;
  19535. ufbxi_cache_tmp_channel *channels;
  19536. size_t num_channels;
  19537. // Temporary array
  19538. char *tmp_arr;
  19539. size_t tmp_arr_size;
  19540. ufbxi_string_pool string_pool;
  19541. ufbx_open_file_cb open_file_cb;
  19542. double frames_per_second;
  19543. ufbx_string stream_filename;
  19544. ufbx_stream stream;
  19545. bool mc_for8;
  19546. ufbx_string xml_filename;
  19547. uint32_t xml_ticks_per_frame;
  19548. ufbxi_cache_xml_type xml_type;
  19549. ufbxi_cache_xml_format xml_format;
  19550. ufbx_string channel_name;
  19551. char *name_buf;
  19552. size_t name_cap;
  19553. uint64_t file_offset;
  19554. const char *pos, *pos_end;
  19555. ufbx_geometry_cache cache;
  19556. ufbxi_geometry_cache_imp *imp;
  19557. char buffer[128];
  19558. } ufbxi_cache_context;
  19559. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_read(ufbxi_cache_context *cc, void *dst, size_t size, bool allow_eof)
  19560. {
  19561. size_t buffered = ufbxi_min_sz(ufbxi_to_size(cc->pos_end - cc->pos), size);
  19562. memcpy(dst, cc->pos, buffered);
  19563. cc->pos += buffered;
  19564. size -= buffered;
  19565. cc->file_offset += buffered;
  19566. if (size == 0) return 1;
  19567. dst = (char*)dst + buffered;
  19568. if (size >= sizeof(cc->buffer)) {
  19569. size_t num_read = cc->stream.read_fn(cc->stream.user, dst, size);
  19570. ufbxi_check_err_msg(&cc->error, num_read <= size, "IO error");
  19571. if (!allow_eof) {
  19572. ufbxi_check_err_msg(&cc->error, num_read == size, "Truncated file");
  19573. }
  19574. cc->file_offset += num_read;
  19575. size -= num_read;
  19576. dst = (char*)dst + num_read;
  19577. } else {
  19578. size_t num_read = cc->stream.read_fn(cc->stream.user, cc->buffer, sizeof(cc->buffer));
  19579. ufbxi_check_err_msg(&cc->error, num_read <= sizeof(cc->buffer), "IO error");
  19580. if (!allow_eof) {
  19581. ufbxi_check_err_msg(&cc->error, num_read >= size, "Truncated file");
  19582. }
  19583. cc->pos = cc->buffer;
  19584. cc->pos_end = cc->buffer + sizeof(cc->buffer);
  19585. memcpy(dst, cc->pos, size);
  19586. cc->pos += size;
  19587. cc->file_offset += size;
  19588. size_t num_written = ufbxi_min_sz(size, num_read);
  19589. size -= num_written;
  19590. dst = (char*)dst + num_written;
  19591. }
  19592. if (size > 0) {
  19593. memset(dst, 0, size);
  19594. }
  19595. return 1;
  19596. }
  19597. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_skip(ufbxi_cache_context *cc, uint64_t size)
  19598. {
  19599. cc->file_offset += size;
  19600. uint64_t buffered = ufbxi_min64((uint64_t)(cc->pos_end - cc->pos), size);
  19601. cc->pos += buffered;
  19602. size -= buffered;
  19603. if (cc->stream.skip_fn) {
  19604. while (size >= UFBXI_MAX_SKIP_SIZE) {
  19605. size -= UFBXI_MAX_SKIP_SIZE;
  19606. ufbxi_check_err_msg(&cc->error, cc->stream.skip_fn(cc->stream.user, UFBXI_MAX_SKIP_SIZE - 1), "Truncated file");
  19607. // Check that we can read at least one byte in case the file is broken
  19608. // and causes us to seek indefinitely forwards as `fseek()` does not
  19609. // report if we hit EOF...
  19610. char single_byte[1]; // ufbxi_uninit
  19611. size_t num_read = cc->stream.read_fn(cc->stream.user, single_byte, 1);
  19612. ufbxi_check_err_msg(&cc->error, num_read <= 1, "IO error");
  19613. ufbxi_check_err_msg(&cc->error, num_read == 1, "Truncated file");
  19614. }
  19615. if (size > 0) {
  19616. ufbxi_check_err_msg(&cc->error, cc->stream.skip_fn(cc->stream.user, (size_t)size), "Truncated file");
  19617. }
  19618. } else {
  19619. char skip_buf[2048]; // ufbxi_uninit
  19620. while (size > 0) {
  19621. size_t to_skip = (size_t)ufbxi_min64(size, sizeof(skip_buf));
  19622. size -= to_skip;
  19623. ufbxi_check_err_msg(&cc->error, cc->stream.read_fn(cc->stream.user, skip_buf, to_skip), "Truncated file");
  19624. }
  19625. }
  19626. return 1;
  19627. }
  19628. #define ufbxi_cache_mc_tag(a,b,c,d) ((uint32_t)(a)<<24u | (uint32_t)(b)<<16 | (uint32_t)(c)<<8u | (uint32_t)(d))
  19629. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_mc_read_tag(ufbxi_cache_context *cc, uint32_t *p_tag)
  19630. {
  19631. char buf[4]; // ufbxi_uninit
  19632. ufbxi_check_err(&cc->error, ufbxi_cache_read(cc, buf, 4, true));
  19633. *p_tag = (uint32_t)(uint8_t)buf[0]<<24u | (uint32_t)(uint8_t)buf[1]<<16 | (uint32_t)(uint8_t)buf[2]<<8u | (uint32_t)(uint8_t)buf[3];
  19634. if (*p_tag == ufbxi_cache_mc_tag('F','O','R','8')) {
  19635. cc->mc_for8 = true;
  19636. }
  19637. return 1;
  19638. }
  19639. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_mc_read_u32(ufbxi_cache_context *cc, uint32_t *p_value)
  19640. {
  19641. char buf[4]; // ufbxi_uninit
  19642. ufbxi_check_err(&cc->error, ufbxi_cache_read(cc, buf, 4, false));
  19643. *p_value = (uint32_t)(uint8_t)buf[0]<<24u | (uint32_t)(uint8_t)buf[1]<<16 | (uint32_t)(uint8_t)buf[2]<<8u | (uint32_t)(uint8_t)buf[3];
  19644. if (cc->mc_for8) {
  19645. ufbxi_check_err(&cc->error, ufbxi_cache_read(cc, buf, 4, false));
  19646. }
  19647. return 1;
  19648. }
  19649. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_mc_read_u64(ufbxi_cache_context *cc, uint64_t *p_value)
  19650. {
  19651. if (!cc->mc_for8) {
  19652. uint32_t v32; // ufbxi_uninit
  19653. ufbxi_check_err(&cc->error, ufbxi_cache_mc_read_u32(cc, &v32));
  19654. *p_value = v32;
  19655. } else {
  19656. char buf[8]; // ufbxi_uninit
  19657. ufbxi_check_err(&cc->error, ufbxi_cache_read(cc, buf, 8, false));
  19658. uint32_t hi = (uint32_t)(uint8_t)buf[0]<<24u | (uint32_t)(uint8_t)buf[1]<<16 | (uint32_t)(uint8_t)buf[2]<<8u | (uint32_t)(uint8_t)buf[3];
  19659. uint32_t lo = (uint32_t)(uint8_t)buf[4]<<24u | (uint32_t)(uint8_t)buf[5]<<16 | (uint32_t)(uint8_t)buf[6]<<8u | (uint32_t)(uint8_t)buf[7];
  19660. *p_value = (uint64_t)hi << 32u | (uint64_t)lo;
  19661. }
  19662. return 1;
  19663. }
  19664. static const uint8_t ufbxi_cache_data_format_size[] = {
  19665. 0, 4, 12, 8, 24,
  19666. };
  19667. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_load_mc(ufbxi_cache_context *cc)
  19668. {
  19669. uint32_t version = 0, time_start = 0, time_end = 0;
  19670. uint32_t count = 0, time = 0;
  19671. char skip_buf[8]; // ufbxi_uninit
  19672. for (;;) {
  19673. uint32_t tag; // ufbxi_uninit
  19674. uint64_t size; // ufbxi_uninit
  19675. ufbxi_check_err(&cc->error, ufbxi_cache_mc_read_tag(cc, &tag));
  19676. if (tag == 0) break;
  19677. if (tag == ufbxi_cache_mc_tag('C','A','C','H') || tag == ufbxi_cache_mc_tag('M','Y','C','H')) {
  19678. continue;
  19679. }
  19680. if (cc->mc_for8) {
  19681. ufbxi_check_err(&cc->error, ufbxi_cache_read(cc, skip_buf, 4, false));
  19682. }
  19683. ufbxi_check_err(&cc->error, ufbxi_cache_mc_read_u64(cc, &size));
  19684. uint64_t begin = cc->file_offset;
  19685. size_t alignment = cc->mc_for8 ? 8 : 4;
  19686. ufbx_cache_data_format format = UFBX_CACHE_DATA_FORMAT_UNKNOWN;
  19687. switch (tag) {
  19688. case ufbxi_cache_mc_tag('F','O','R','4'): cc->mc_for8 = false; break;
  19689. case ufbxi_cache_mc_tag('F','O','R','8'): cc->mc_for8 = true; break;
  19690. case ufbxi_cache_mc_tag('V','R','S','N'): ufbxi_check_err(&cc->error, ufbxi_cache_mc_read_u32(cc, &version)); break;
  19691. case ufbxi_cache_mc_tag('S','T','I','M'):
  19692. ufbxi_check_err(&cc->error, ufbxi_cache_mc_read_u32(cc, &time_start));
  19693. time = time_start;
  19694. break;
  19695. case ufbxi_cache_mc_tag('E','T','I','M'): ufbxi_check_err(&cc->error, ufbxi_cache_mc_read_u32(cc, &time_end)); break;
  19696. case ufbxi_cache_mc_tag('T','I','M','E'): ufbxi_check_err(&cc->error, ufbxi_cache_mc_read_u32(cc, &time)); break;
  19697. case ufbxi_cache_mc_tag('C','H','N','M'): {
  19698. ufbxi_check_err(&cc->error, size > 0 && size < SIZE_MAX);
  19699. size_t length = (size_t)size - 1;
  19700. size_t padded_length = ((size_t)size + alignment - 1) & ~(alignment - 1);
  19701. ufbxi_check_err(&cc->error, ufbxi_grow_array(cc->ator_tmp, &cc->name_buf, &cc->name_cap, padded_length));
  19702. ufbxi_check_err(&cc->error, ufbxi_cache_read(cc, cc->name_buf, padded_length, false));
  19703. cc->channel_name.data = cc->name_buf;
  19704. cc->channel_name.length = length;
  19705. ufbxi_check_err(&cc->error, ufbxi_push_string_place_str(&cc->string_pool, &cc->channel_name, false));
  19706. } break;
  19707. case ufbxi_cache_mc_tag('S','I','Z','E'): ufbxi_check_err(&cc->error, ufbxi_cache_mc_read_u32(cc, &count)); break;
  19708. case ufbxi_cache_mc_tag('F','V','C','A'): format = UFBX_CACHE_DATA_FORMAT_VEC3_FLOAT; break;
  19709. case ufbxi_cache_mc_tag('D','V','C','A'): format = UFBX_CACHE_DATA_FORMAT_VEC3_DOUBLE; break;
  19710. case ufbxi_cache_mc_tag('F','B','C','A'): format = UFBX_CACHE_DATA_FORMAT_REAL_FLOAT; break;
  19711. case ufbxi_cache_mc_tag('D','B','C','A'): format = UFBX_CACHE_DATA_FORMAT_REAL_DOUBLE; break;
  19712. case ufbxi_cache_mc_tag('D','B','L','A'): format = UFBX_CACHE_DATA_FORMAT_REAL_DOUBLE; break;
  19713. default: ufbxi_fail_err(&cc->error, "Unknown tag");
  19714. }
  19715. if (format != UFBX_CACHE_DATA_FORMAT_UNKNOWN) {
  19716. ufbx_cache_frame *frame = ufbxi_push_zero(&cc->tmp_stack, ufbx_cache_frame, 1);
  19717. ufbxi_check_err(&cc->error, frame);
  19718. uint32_t elem_size = ufbxi_cache_data_format_size[format];
  19719. uint64_t total_size = (uint64_t)elem_size * (uint64_t)count;
  19720. ufbxi_check_err(&cc->error, size >= elem_size * count);
  19721. frame->channel = cc->channel_name;
  19722. frame->time = (double)time * (1.0/6000.0);
  19723. frame->filename = cc->stream_filename;
  19724. frame->data_format = format;
  19725. frame->data_encoding = UFBX_CACHE_DATA_ENCODING_BIG_ENDIAN;
  19726. frame->data_offset = cc->file_offset;
  19727. frame->data_count = count;
  19728. frame->data_element_bytes = elem_size;
  19729. frame->data_total_bytes = total_size;
  19730. frame->file_format = UFBX_CACHE_FILE_FORMAT_MC;
  19731. uint64_t end = begin + ((size + alignment - 1) & ~(uint64_t)(alignment - 1));
  19732. ufbxi_check_err(&cc->error, end >= cc->file_offset);
  19733. uint64_t left = end - cc->file_offset;
  19734. ufbxi_check_err(&cc->error, ufbxi_cache_skip(cc, left));
  19735. }
  19736. }
  19737. return 1;
  19738. }
  19739. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_load_pc2(ufbxi_cache_context *cc)
  19740. {
  19741. char header[32]; // ufbxi_uninit
  19742. ufbxi_check_err(&cc->error, ufbxi_cache_read(cc, header, sizeof(header), false));
  19743. uint32_t version = ufbxi_read_u32(header + 12);
  19744. uint32_t num_points = ufbxi_read_u32(header + 16);
  19745. double start_frame = ufbxi_read_f32(header + 20);
  19746. double frames_per_sample = ufbxi_read_f32(header + 24);
  19747. uint32_t num_samples = ufbxi_read_u32(header + 28);
  19748. (void)version;
  19749. ufbx_cache_frame *frames = ufbxi_push_zero(&cc->tmp_stack, ufbx_cache_frame, num_samples);
  19750. ufbxi_check_err(&cc->error, frames);
  19751. uint64_t total_points = (uint64_t)num_points * (uint64_t)num_samples;
  19752. ufbxi_check_err(&cc->error, total_points < UINT64_MAX / 12);
  19753. uint64_t offset = cc->file_offset;
  19754. // Skip almost to the end of the data and try to read one byte as there's
  19755. // nothing after the data so we can't detect EOF..
  19756. if (total_points > 0) {
  19757. char last_byte[1]; // ufbxi_uninit
  19758. ufbxi_check_err(&cc->error, ufbxi_cache_skip(cc, total_points * 12 - 1));
  19759. ufbxi_check_err(&cc->error, ufbxi_cache_read(cc, last_byte, 1, false));
  19760. }
  19761. for (uint32_t i = 0; i < num_samples; i++) {
  19762. ufbx_cache_frame *frame = &frames[i];
  19763. double sample_frame = start_frame + (double)i * frames_per_sample;
  19764. frame->channel = cc->channel_name;
  19765. frame->time = sample_frame / cc->frames_per_second;
  19766. frame->filename = cc->stream_filename;
  19767. frame->data_format = UFBX_CACHE_DATA_FORMAT_VEC3_FLOAT;
  19768. frame->data_encoding = UFBX_CACHE_DATA_ENCODING_LITTLE_ENDIAN;
  19769. frame->data_offset = offset;
  19770. frame->data_count = num_points;
  19771. frame->data_element_bytes = 12;
  19772. frame->data_total_bytes = num_points * 12;
  19773. frame->file_format = UFBX_CACHE_FILE_FORMAT_PC2;
  19774. offset += num_points * 12;
  19775. }
  19776. return 1;
  19777. }
  19778. static ufbxi_noinline bool ufbxi_tmp_channel_less(void *user, const void *va, const void *vb)
  19779. {
  19780. (void)user;
  19781. const ufbxi_cache_tmp_channel *a = (const ufbxi_cache_tmp_channel *)va, *b = (const ufbxi_cache_tmp_channel *)vb;
  19782. return ufbxi_str_less(a->name, b->name);
  19783. }
  19784. static ufbxi_noinline int ufbxi_cache_sort_tmp_channels(ufbxi_cache_context *cc, ufbxi_cache_tmp_channel *channels, size_t count)
  19785. {
  19786. ufbxi_check_err(&cc->error, ufbxi_grow_array(cc->ator_tmp, &cc->tmp_arr, &cc->tmp_arr_size, count * sizeof(ufbxi_cache_tmp_channel)));
  19787. ufbxi_stable_sort(sizeof(ufbxi_cache_tmp_channel), 16, channels, cc->tmp_arr, count, &ufbxi_tmp_channel_less, NULL);
  19788. return 1;
  19789. }
  19790. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_load_xml_imp(ufbxi_cache_context *cc, ufbxi_xml_document *doc)
  19791. {
  19792. cc->xml_ticks_per_frame = 250;
  19793. cc->xml_filename = cc->stream_filename;
  19794. ufbxi_xml_tag *tag_root = ufbxi_xml_find_child(doc->root, "Autodesk_Cache_File");
  19795. if (tag_root) {
  19796. ufbxi_xml_tag *tag_type = ufbxi_xml_find_child(tag_root, "cacheType");
  19797. ufbxi_xml_tag *tag_fps = ufbxi_xml_find_child(tag_root, "cacheTimePerFrame");
  19798. ufbxi_xml_tag *tag_channels = ufbxi_xml_find_child(tag_root, "Channels");
  19799. size_t num_extra = 0;
  19800. ufbxi_for(ufbxi_xml_tag, tag, tag_root->children, tag_root->num_children) {
  19801. if (tag->num_children != 1) continue;
  19802. if (strcmp(tag->name.data, "extra") != 0) continue;
  19803. ufbx_string *extra = ufbxi_push(&cc->tmp_stack, ufbx_string, 1);
  19804. ufbxi_check_err(&cc->error, extra);
  19805. *extra = tag->children[0].text;
  19806. ufbxi_check_err(&cc->error, ufbxi_push_string_place_str(&cc->string_pool, extra, false));
  19807. num_extra++;
  19808. }
  19809. cc->cache.extra_info.count = num_extra;
  19810. cc->cache.extra_info.data = ufbxi_push_pop(&cc->result, &cc->tmp_stack, ufbx_string, num_extra);
  19811. ufbxi_check_err(&cc->error, cc->cache.extra_info.data);
  19812. if (tag_type) {
  19813. ufbxi_xml_attrib *type = ufbxi_xml_find_attrib(tag_type, "Type");
  19814. ufbxi_xml_attrib *format = ufbxi_xml_find_attrib(tag_type, "Format");
  19815. if (type) {
  19816. if (!strcmp(type->value.data, "OneFilePerFrame")) {
  19817. cc->xml_type = UFBXI_CACHE_XML_TYPE_FILE_PER_FRAME;
  19818. } else if (!strcmp(type->value.data, "OneFile")) {
  19819. cc->xml_type = UFBXI_CACHE_XML_TYPE_SINGLE_FILE;
  19820. }
  19821. }
  19822. if (format) {
  19823. if (!strcmp(format->value.data, "mcc")) {
  19824. cc->xml_format = UFBXI_CACHE_XML_FORMAT_MCC;
  19825. } else if (!strcmp(format->value.data, "mcx")) {
  19826. cc->xml_format = UFBXI_CACHE_XML_FORMAT_MCX;
  19827. }
  19828. }
  19829. }
  19830. if (tag_fps) {
  19831. ufbxi_xml_attrib *fps = ufbxi_xml_find_attrib(tag_fps, "TimePerFrame");
  19832. if (fps) {
  19833. int value = atoi(fps->value.data);
  19834. if (value > 0) {
  19835. cc->xml_ticks_per_frame = (uint32_t)value;
  19836. }
  19837. }
  19838. }
  19839. if (tag_channels) {
  19840. cc->channels = ufbxi_push_zero(&cc->tmp, ufbxi_cache_tmp_channel, tag_channels->num_children);
  19841. ufbxi_check_err(&cc->error, cc->channels);
  19842. ufbxi_for(ufbxi_xml_tag, tag, tag_channels->children, tag_channels->num_children) {
  19843. ufbxi_xml_attrib *name = ufbxi_xml_find_attrib(tag, "ChannelName");
  19844. ufbxi_xml_attrib *type = ufbxi_xml_find_attrib(tag, "ChannelType");
  19845. ufbxi_xml_attrib *interpretation = ufbxi_xml_find_attrib(tag, "ChannelInterpretation");
  19846. if (!(name && type && interpretation)) continue;
  19847. ufbxi_cache_tmp_channel *channel = &cc->channels[cc->num_channels++];
  19848. channel->name = name->value;
  19849. channel->interpretation = interpretation->value;
  19850. ufbxi_check_err(&cc->error, ufbxi_push_string_place_str(&cc->string_pool, &channel->name, false));
  19851. ufbxi_check_err(&cc->error, ufbxi_push_string_place_str(&cc->string_pool, &channel->interpretation, false));
  19852. ufbxi_xml_attrib *sampling_rate = ufbxi_xml_find_attrib(tag, "SamplingRate");
  19853. ufbxi_xml_attrib *start_time = ufbxi_xml_find_attrib(tag, "StartTime");
  19854. ufbxi_xml_attrib *end_time = ufbxi_xml_find_attrib(tag, "EndTime");
  19855. if (sampling_rate && start_time && end_time) {
  19856. channel->sample_rate = (uint32_t)atoi(sampling_rate->value.data);
  19857. channel->start_time = (uint32_t)atoi(start_time->value.data);
  19858. channel->end_time = (uint32_t)atoi(end_time->value.data);
  19859. channel->current_time = channel->start_time;
  19860. channel->try_load = true;
  19861. }
  19862. }
  19863. }
  19864. }
  19865. ufbxi_check_err(&cc->error, ufbxi_cache_sort_tmp_channels(cc, cc->channels, cc->num_channels));
  19866. return 1;
  19867. }
  19868. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_load_xml(ufbxi_cache_context *cc)
  19869. {
  19870. ufbxi_xml_load_opts opts = { 0 };
  19871. opts.ator = cc->ator_tmp;
  19872. opts.read_fn = cc->stream.read_fn;
  19873. opts.read_user = cc->stream.user;
  19874. opts.prefix = cc->pos;
  19875. opts.prefix_length = ufbxi_to_size(cc->pos_end - cc->pos);
  19876. ufbxi_xml_document *doc = ufbxi_load_xml(&opts, &cc->error);
  19877. ufbxi_check_err(&cc->error, doc);
  19878. int xml_ok = ufbxi_cache_load_xml_imp(cc, doc);
  19879. ufbxi_free_xml(doc);
  19880. ufbxi_check_err(&cc->error, xml_ok);
  19881. return 1;
  19882. }
  19883. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_load_file(ufbxi_cache_context *cc, ufbx_string filename)
  19884. {
  19885. cc->stream_filename = filename;
  19886. ufbxi_check_err(&cc->error, ufbxi_push_string_place_str(&cc->string_pool, &cc->stream_filename, false));
  19887. // Assume all files have at least 16 bytes of header
  19888. size_t magic_len = cc->stream.read_fn(cc->stream.user, cc->buffer, 16);
  19889. ufbxi_check_err_msg(&cc->error, magic_len <= 16, "IO error");
  19890. ufbxi_check_err_msg(&cc->error, magic_len == 16, "Truncated file");
  19891. cc->pos = cc->buffer;
  19892. cc->pos_end = cc->buffer + 16;
  19893. cc->file_offset = 0;
  19894. if (!memcmp(cc->buffer, "POINTCACHE2", 11)) {
  19895. ufbxi_check_err(&cc->error, ufbxi_cache_load_pc2(cc));
  19896. } else if (!memcmp(cc->buffer, "FOR4", 4) || !memcmp(cc->buffer, "FOR8", 4)) {
  19897. ufbxi_check_err(&cc->error, ufbxi_cache_load_mc(cc));
  19898. } else {
  19899. ufbxi_check_err(&cc->error, ufbxi_cache_load_xml(cc));
  19900. }
  19901. return 1;
  19902. }
  19903. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_try_open_file(ufbxi_cache_context *cc, ufbx_string filename, const ufbx_blob *original_filename, bool *p_found)
  19904. {
  19905. memset(&cc->stream, 0, sizeof(cc->stream));
  19906. ufbxi_regression_assert(strlen(filename.data) == filename.length);
  19907. if (!ufbxi_open_file(&cc->open_file_cb, &cc->stream, filename.data, filename.length, original_filename, cc->ator_tmp, UFBX_OPEN_FILE_GEOMETRY_CACHE)) {
  19908. return 1;
  19909. }
  19910. int ok = ufbxi_cache_load_file(cc, filename);
  19911. *p_found = true;
  19912. if (cc->stream.close_fn) {
  19913. cc->stream.close_fn(cc->stream.user);
  19914. }
  19915. return ok;
  19916. }
  19917. ufbxi_nodiscard static ufbxi_noinline int ufbxi_cache_load_frame_files(ufbxi_cache_context *cc)
  19918. {
  19919. if (cc->xml_filename.length == 0) return 1;
  19920. const char *extension = NULL;
  19921. switch (cc->xml_format) {
  19922. case UFBXI_CACHE_XML_FORMAT_MCC: extension = "mc"; break;
  19923. case UFBXI_CACHE_XML_FORMAT_MCX: extension = "mcx"; break;
  19924. default: return 1;
  19925. }
  19926. // Ensure worst case space for `path/filenameFrame123Tick456.mcx`
  19927. size_t name_buf_len = cc->xml_filename.length + 64;
  19928. char *name_buf = ufbxi_push(&cc->tmp, char, name_buf_len);
  19929. ufbxi_check_err(&cc->error, name_buf);
  19930. // Find the prefix before `.xml`
  19931. size_t prefix_len = cc->xml_filename.length;
  19932. for (size_t i = prefix_len; i > 0; --i) {
  19933. if (cc->xml_filename.data[i - 1] == '.') {
  19934. prefix_len = i - 1;
  19935. break;
  19936. }
  19937. }
  19938. memcpy(name_buf, cc->xml_filename.data, prefix_len);
  19939. char *suffix_data = name_buf + prefix_len;
  19940. size_t suffix_len = name_buf_len - prefix_len;
  19941. ufbx_string filename;
  19942. filename.data = name_buf;
  19943. if (cc->xml_type == UFBXI_CACHE_XML_TYPE_SINGLE_FILE) {
  19944. filename.length = prefix_len + (size_t)ufbxi_snprintf(suffix_data, suffix_len, ".%s", extension);
  19945. bool found = false;
  19946. ufbxi_check_err(&cc->error, ufbxi_cache_try_open_file(cc, filename, NULL, &found));
  19947. } else if (cc->xml_type == UFBXI_CACHE_XML_TYPE_FILE_PER_FRAME) {
  19948. uint32_t lowest_time = 0;
  19949. for (;;) {
  19950. // Find the first `time >= lowest_time` value that has data in some channel
  19951. uint32_t time = UINT32_MAX;
  19952. ufbxi_for(ufbxi_cache_tmp_channel, chan, cc->channels, cc->num_channels) {
  19953. if (!chan->try_load || chan->consecutive_fails > 10) continue;
  19954. uint32_t sample_rate = chan->sample_rate ? chan->sample_rate : cc->xml_ticks_per_frame;
  19955. if (chan->current_time < lowest_time) {
  19956. uint32_t delta = (lowest_time - chan->current_time - 1) / sample_rate;
  19957. chan->current_time += delta * sample_rate;
  19958. if (UINT32_MAX - chan->current_time >= sample_rate) {
  19959. chan->current_time += sample_rate;
  19960. } else {
  19961. chan->try_load = false;
  19962. continue;
  19963. }
  19964. }
  19965. if (chan->current_time <= chan->end_time) {
  19966. time = ufbxi_min32(time, chan->current_time);
  19967. }
  19968. }
  19969. if (time == UINT32_MAX) break;
  19970. // Try to load a file at the specified frame/tick
  19971. uint32_t frame = time / cc->xml_ticks_per_frame;
  19972. uint32_t tick = time % cc->xml_ticks_per_frame;
  19973. if (tick == 0) {
  19974. filename.length = prefix_len + (size_t)ufbxi_snprintf(suffix_data, suffix_len, "Frame%u.%s", frame, extension);
  19975. } else {
  19976. filename.length = prefix_len + (size_t)ufbxi_snprintf(suffix_data, suffix_len, "Frame%uTick%u.%s", frame, tick, extension);
  19977. }
  19978. bool found = false;
  19979. ufbxi_check_err(&cc->error, ufbxi_cache_try_open_file(cc, filename, NULL, &found));
  19980. // Update channel status
  19981. ufbxi_for(ufbxi_cache_tmp_channel, chan, cc->channels, cc->num_channels) {
  19982. if (chan->current_time == time) {
  19983. chan->consecutive_fails = found ? 0 : chan->consecutive_fails + 1;
  19984. }
  19985. }
  19986. lowest_time = time + 1;
  19987. }
  19988. }
  19989. return 1;
  19990. }
  19991. static ufbxi_noinline bool ufbxi_cmp_cache_frame_less(void *user, const void *va, const void *vb)
  19992. {
  19993. (void)user;
  19994. const ufbx_cache_frame *a = (const ufbx_cache_frame *)va, *b = (const ufbx_cache_frame *)vb;
  19995. if (a->channel.data != b->channel.data) {
  19996. // Channel names should be interned
  19997. ufbxi_regression_assert(!ufbxi_str_equal(a->channel, b->channel));
  19998. return ufbxi_str_less(a->channel, b->channel);
  19999. }
  20000. return a->time < b->time;
  20001. }
  20002. static ufbxi_noinline int ufbxi_cache_sort_frames(ufbxi_cache_context *cc, ufbx_cache_frame *frames, size_t count)
  20003. {
  20004. ufbxi_check_err(&cc->error, ufbxi_grow_array(cc->ator_tmp, &cc->tmp_arr, &cc->tmp_arr_size, count * sizeof(ufbx_cache_frame)));
  20005. ufbxi_stable_sort(sizeof(ufbx_cache_frame), 16, frames, cc->tmp_arr, count, &ufbxi_cmp_cache_frame_less, NULL);
  20006. return 1;
  20007. }
  20008. typedef struct {
  20009. ufbx_cache_interpretation interpretation;
  20010. const char *pattern;
  20011. } ufbxi_cache_interpretation_name;
  20012. static const ufbxi_cache_interpretation_name ufbxi_cache_interpretation_names[] = {
  20013. { UFBX_CACHE_INTERPRETATION_POINTS, "\\cpoints?" },
  20014. { UFBX_CACHE_INTERPRETATION_VERTEX_POSITION, "\\cpositions?" },
  20015. { UFBX_CACHE_INTERPRETATION_VERTEX_NORMAL, "\\cnormals?" },
  20016. };
  20017. static ufbxi_noinline int ufbxi_cache_setup_channels(ufbxi_cache_context *cc)
  20018. {
  20019. ufbxi_cache_tmp_channel *tmp_chan = cc->channels, *tmp_end = ufbxi_add_ptr(tmp_chan, cc->num_channels);
  20020. size_t begin = 0, num_channels = 0;
  20021. while (begin < cc->cache.frames.count) {
  20022. ufbx_cache_frame *frame = &cc->cache.frames.data[begin];
  20023. size_t end = begin + 1;
  20024. while (end < cc->cache.frames.count && cc->cache.frames.data[end].channel.data == frame->channel.data) {
  20025. end++;
  20026. }
  20027. ufbx_cache_channel *chan = ufbxi_push_zero(&cc->tmp_stack, ufbx_cache_channel, 1);
  20028. ufbxi_check_err(&cc->error, chan);
  20029. chan->name = frame->channel;
  20030. chan->interpretation_name = ufbx_empty_string;
  20031. chan->frames.data = frame;
  20032. chan->frames.count = end - begin;
  20033. while (tmp_chan < tmp_end && ufbxi_str_less(tmp_chan->name, chan->name)) {
  20034. tmp_chan++;
  20035. }
  20036. if (tmp_chan < tmp_end && ufbxi_str_equal(tmp_chan->name, chan->name)) {
  20037. chan->interpretation_name = tmp_chan->interpretation;
  20038. }
  20039. if (frame->file_format == UFBX_CACHE_FILE_FORMAT_PC2) {
  20040. chan->interpretation = UFBX_CACHE_INTERPRETATION_VERTEX_POSITION;
  20041. } else {
  20042. ufbxi_for(const ufbxi_cache_interpretation_name, name, ufbxi_cache_interpretation_names, ufbxi_arraycount(ufbxi_cache_interpretation_names)) {
  20043. if (ufbxi_match(&chan->interpretation_name, name->pattern)) {
  20044. chan->interpretation = name->interpretation;
  20045. break;
  20046. }
  20047. }
  20048. }
  20049. ufbx_mirror_axis mirror_axis = UFBX_MIRROR_AXIS_NONE;
  20050. ufbx_real scale_factor = 1.0f;
  20051. if (chan->interpretation != UFBX_CACHE_INTERPRETATION_UNKNOWN) {
  20052. mirror_axis = cc->opts.mirror_axis;
  20053. if (cc->opts.use_scale_factor) {
  20054. scale_factor = cc->opts.scale_factor;
  20055. }
  20056. }
  20057. chan->mirror_axis = mirror_axis;
  20058. chan->scale_factor = scale_factor;
  20059. ufbxi_for_list(ufbx_cache_frame, f, chan->frames) {
  20060. f->mirror_axis = mirror_axis;
  20061. f->scale_factor = scale_factor;
  20062. }
  20063. num_channels++;
  20064. begin = end;
  20065. }
  20066. cc->cache.channels.data = ufbxi_push_pop(&cc->result, &cc->tmp_stack, ufbx_cache_channel, num_channels);
  20067. ufbxi_check_err(&cc->error, cc->cache.channels.data);
  20068. cc->cache.channels.count = num_channels;
  20069. return 1;
  20070. }
  20071. static ufbxi_noinline int ufbxi_cache_load_imp(ufbxi_cache_context *cc, ufbx_string filename)
  20072. {
  20073. cc->tmp.ator = cc->ator_tmp;
  20074. cc->tmp_stack.ator = cc->ator_tmp;
  20075. cc->channel_name.data = ufbxi_empty_char;
  20076. if (!cc->open_file_cb.fn) {
  20077. cc->open_file_cb.fn = ufbx_default_open_file;
  20078. }
  20079. // Make sure the filename we pass to `open_file_fn()` is NULL-terminated
  20080. char *filename_data = ufbxi_push(&cc->tmp, char, filename.length + 1);
  20081. ufbxi_check_err(&cc->error, filename_data);
  20082. memcpy(filename_data, filename.data, filename.length);
  20083. filename_data[filename.length] = '\0';
  20084. ufbx_string filename_copy = { filename_data, filename.length };
  20085. // TODO: NULL termination!
  20086. bool found = false;
  20087. ufbxi_check_err(&cc->error, ufbxi_cache_try_open_file(cc, filename_copy, NULL, &found));
  20088. if (!found) {
  20089. ufbxi_set_err_info(&cc->error, filename.data, filename.length);
  20090. ufbxi_fail_err_msg(&cc->error, "open_file_fn()", "File not found");
  20091. }
  20092. cc->cache.root_filename = cc->stream_filename;
  20093. ufbxi_check_err(&cc->error, ufbxi_cache_load_frame_files(cc));
  20094. size_t num_frames = cc->tmp_stack.num_items;
  20095. cc->cache.frames.count = num_frames;
  20096. cc->cache.frames.data = ufbxi_push_pop(&cc->result, &cc->tmp_stack, ufbx_cache_frame, num_frames);
  20097. ufbxi_check_err(&cc->error, cc->cache.frames.data);
  20098. ufbxi_check_err(&cc->error, ufbxi_cache_sort_frames(cc, cc->cache.frames.data, cc->cache.frames.count));
  20099. ufbxi_check_err(&cc->error, ufbxi_cache_setup_channels(cc));
  20100. // Must be last allocation!
  20101. cc->imp = ufbxi_push(&cc->result, ufbxi_geometry_cache_imp, 1);
  20102. ufbxi_check_err(&cc->error, cc->imp);
  20103. ufbxi_init_ref(&cc->imp->refcount, UFBXI_CACHE_IMP_MAGIC, NULL);
  20104. cc->imp->cache = cc->cache;
  20105. cc->imp->magic = UFBXI_CACHE_IMP_MAGIC;
  20106. cc->imp->owned_by_scene = cc->owned_by_scene;
  20107. cc->imp->refcount.ator = cc->ator_result;
  20108. cc->imp->refcount.buf = cc->result;
  20109. cc->imp->refcount.buf.ator = &cc->imp->refcount.ator;
  20110. cc->imp->string_buf = cc->string_pool.buf;
  20111. cc->imp->string_buf.ator = &cc->imp->refcount.ator;
  20112. return 1;
  20113. }
  20114. ufbxi_noinline static ufbx_geometry_cache *ufbxi_cache_load(ufbxi_cache_context *cc, ufbx_string filename)
  20115. {
  20116. int ok = ufbxi_cache_load_imp(cc, filename);
  20117. ufbxi_buf_free(&cc->tmp);
  20118. ufbxi_buf_free(&cc->tmp_stack);
  20119. ufbxi_free(cc->ator_tmp, char, cc->name_buf, cc->name_cap);
  20120. ufbxi_free(cc->ator_tmp, char, cc->tmp_arr, cc->tmp_arr_size);
  20121. if (!cc->owned_by_scene) {
  20122. ufbxi_string_pool_temp_free(&cc->string_pool);
  20123. ufbxi_free_ator(cc->ator_tmp);
  20124. }
  20125. if (ok) {
  20126. return &cc->imp->cache;
  20127. } else {
  20128. ufbxi_fix_error_type(&cc->error, "Failed to load geometry cache");
  20129. if (!cc->owned_by_scene) {
  20130. ufbxi_buf_free(&cc->string_pool.buf);
  20131. ufbxi_free_ator(&cc->ator_result);
  20132. }
  20133. return NULL;
  20134. }
  20135. }
  20136. ufbxi_noinline static ufbx_geometry_cache *ufbxi_load_geometry_cache(ufbx_string filename, const ufbx_geometry_cache_opts *user_opts, ufbx_error *p_error)
  20137. {
  20138. ufbx_geometry_cache_opts opts; // ufbxi_uninit
  20139. if (user_opts) {
  20140. opts = *user_opts;
  20141. } else {
  20142. memset(&opts, 0, sizeof(opts));
  20143. }
  20144. ufbxi_cache_context cc = { UFBX_ERROR_NONE };
  20145. ufbxi_allocator ator_tmp = { 0 };
  20146. ufbxi_init_ator(&cc.error, &ator_tmp, &opts.temp_allocator, "temp");
  20147. ufbxi_init_ator(&cc.error, &cc.ator_result, &opts.result_allocator, "result");
  20148. cc.ator_tmp = &ator_tmp;
  20149. cc.opts = opts;
  20150. cc.open_file_cb = opts.open_file_cb;
  20151. cc.string_pool.error = &cc.error;
  20152. ufbxi_map_init(&cc.string_pool.map, cc.ator_tmp, &ufbxi_map_cmp_string, NULL);
  20153. cc.string_pool.buf.ator = &cc.ator_result;
  20154. cc.string_pool.buf.unordered = true;
  20155. cc.string_pool.initial_size = 64;
  20156. cc.result.ator = &cc.ator_result;
  20157. cc.frames_per_second = opts.frames_per_second > 0.0 ? opts.frames_per_second : 30.0;
  20158. ufbx_geometry_cache *cache = ufbxi_cache_load(&cc, filename);
  20159. if (p_error) {
  20160. if (cache) {
  20161. ufbxi_clear_error(p_error);
  20162. } else {
  20163. *p_error = cc.error;
  20164. }
  20165. }
  20166. return cache;
  20167. }
  20168. static ufbxi_noinline void ufbxi_free_geometry_cache_imp(ufbxi_geometry_cache_imp *imp)
  20169. {
  20170. ufbx_assert(imp->magic == UFBXI_CACHE_IMP_MAGIC);
  20171. ufbxi_buf_free(&imp->string_buf);
  20172. }
  20173. #else
  20174. typedef struct {
  20175. ufbxi_refcount refcount;
  20176. uint32_t magic;
  20177. bool owned_by_scene;
  20178. } ufbxi_geometry_cache_imp;
  20179. static ufbxi_noinline ufbx_geometry_cache *ufbxi_load_geometry_cache(ufbx_string filename, const ufbx_geometry_cache_opts *user_opts, ufbx_error *p_error)
  20180. {
  20181. if (p_error) {
  20182. memset(p_error, 0, sizeof(ufbx_error));
  20183. ufbxi_fmt_err_info(p_error, "UFBX_ENABLE_GEOMETRY_CACHE");
  20184. ufbxi_report_err_msg(p_error, "UFBXI_FEATURE_GEOMETRY_CACHE", "Feature disabled");
  20185. }
  20186. return NULL;
  20187. }
  20188. static ufbxi_forceinline void ufbxi_free_geometry_cache_imp(ufbxi_geometry_cache_imp *imp)
  20189. {
  20190. }
  20191. #endif
  20192. // -- External files
  20193. typedef enum {
  20194. UFBXI_EXTERNAL_FILE_GEOMETRY_CACHE,
  20195. } ufbxi_external_file_type;
  20196. typedef struct {
  20197. ufbxi_external_file_type type;
  20198. ufbx_string filename;
  20199. ufbx_string absolute_filename;
  20200. size_t index;
  20201. void *data;
  20202. size_t data_size;
  20203. } ufbxi_external_file;
  20204. static bool ufbxi_less_external_file(void *user, const void *va, const void *vb)
  20205. {
  20206. (void)user;
  20207. const ufbxi_external_file *a = (const ufbxi_external_file*)va, *b = (const ufbxi_external_file*)vb;
  20208. if (a->type != b->type) return a->type < b->type;
  20209. int cmp = ufbxi_str_cmp(a->filename, b->filename);
  20210. if (cmp != 0) return cmp < 0;
  20211. if (a->index != b->index) return a->index < b->index;
  20212. return false;
  20213. }
  20214. ufbxi_nodiscard static ufbxi_noinline int ufbxi_load_external_cache(ufbxi_context *uc, ufbxi_external_file *file)
  20215. {
  20216. #if UFBXI_FEATURE_GEOMETRY_CACHE
  20217. ufbxi_cache_context cc = { UFBX_ERROR_NONE };
  20218. cc.owned_by_scene = true;
  20219. cc.open_file_cb = uc->opts.open_file_cb;
  20220. cc.frames_per_second = uc->scene.settings.frames_per_second;
  20221. // Temporarily "borrow" allocators for the geometry cache
  20222. cc.ator_tmp = &uc->ator_tmp;
  20223. cc.string_pool = uc->string_pool;
  20224. cc.result = uc->result;
  20225. cc.opts.mirror_axis = uc->mirror_axis;
  20226. cc.opts.use_scale_factor = true;
  20227. cc.opts.scale_factor = uc->scene.metadata.geometry_scale;
  20228. ufbx_geometry_cache *cache = ufbxi_cache_load(&cc, file->filename);
  20229. if (!cache) {
  20230. if (cc.error.type == UFBX_ERROR_FILE_NOT_FOUND) {
  20231. memset(&cc.error, 0, sizeof(cc.error));
  20232. cache = ufbxi_cache_load(&cc, file->absolute_filename);
  20233. }
  20234. }
  20235. // Return the "borrowed" allocators
  20236. uc->string_pool = cc.string_pool;
  20237. uc->result = cc.result;
  20238. if (!cache) {
  20239. if (cc.error.type == UFBX_ERROR_FILE_NOT_FOUND) {
  20240. if (uc->opts.ignore_missing_external_files) {
  20241. ufbxi_check(ufbxi_warnf(UFBX_WARNING_MISSING_EXTERNAL_FILE, "Failed to open geometry cache: %s", file->filename.data));
  20242. return 1;
  20243. } else {
  20244. cc.error.type = UFBX_ERROR_EXTERNAL_FILE_NOT_FOUND;
  20245. cc.error.description.data = "External file not found";
  20246. cc.error.description.length = strlen("External file not found");
  20247. }
  20248. }
  20249. uc->error = cc.error;
  20250. return 0;
  20251. }
  20252. file->data = cache;
  20253. return 1;
  20254. #else
  20255. if (uc->opts.ignore_missing_external_files) return 1;
  20256. ufbxi_fmt_err_info(&uc->error, "UFBX_ENABLE_GEOMETRY_CACHE");
  20257. ufbxi_fail_msg("UFBXI_FEATURE_GEOMETRY_CACHE", "Feature disabled");
  20258. #endif
  20259. }
  20260. static ufbxi_noinline ufbxi_external_file *ufbxi_find_external_file(ufbxi_external_file *files, size_t num_files, ufbxi_external_file_type type, const char *name)
  20261. {
  20262. size_t ix = SIZE_MAX;
  20263. ufbxi_macro_lower_bound_eq(ufbxi_external_file, 32, &ix, files, 0, num_files,
  20264. ( type != a->type ? type < a->type : strcmp(a->filename.data, name) < 0 ),
  20265. ( a->type == type && a->filename.data == name ));
  20266. return ix != SIZE_MAX ? &files[ix] : NULL;
  20267. }
  20268. ufbxi_nodiscard static ufbxi_noinline int ufbxi_load_external_files(ufbxi_context *uc)
  20269. {
  20270. size_t num_files = 0;
  20271. // Gather external files to deduplicate them
  20272. ufbxi_for_ptr_list(ufbx_cache_file, p_cache, uc->scene.cache_files) {
  20273. ufbx_cache_file *cache = *p_cache;
  20274. if (cache->filename.length > 0) {
  20275. ufbxi_external_file *file = ufbxi_push_zero(&uc->tmp_stack, ufbxi_external_file, 1);
  20276. ufbxi_check(file);
  20277. file->index = num_files++;
  20278. file->type = UFBXI_EXTERNAL_FILE_GEOMETRY_CACHE;
  20279. file->filename = cache->filename;
  20280. file->absolute_filename = cache->absolute_filename;
  20281. }
  20282. }
  20283. // Sort and load the external files
  20284. ufbxi_external_file *files = ufbxi_push_pop(&uc->tmp, &uc->tmp_stack, ufbxi_external_file, num_files);
  20285. ufbxi_check(files);
  20286. ufbxi_unstable_sort(files, num_files, sizeof(ufbxi_external_file), &ufbxi_less_external_file, NULL);
  20287. ufbxi_external_file_type prev_type = UFBXI_EXTERNAL_FILE_GEOMETRY_CACHE;
  20288. const char *prev_name = NULL;
  20289. ufbxi_for(ufbxi_external_file, file, files, num_files) {
  20290. if (file->filename.data == prev_name && file->type == prev_type) continue;
  20291. if (file->type == UFBXI_EXTERNAL_FILE_GEOMETRY_CACHE) {
  20292. ufbxi_check(ufbxi_load_external_cache(uc, file));
  20293. }
  20294. prev_name = file->filename.data;
  20295. prev_type = file->type;
  20296. }
  20297. // Patch the loaded files
  20298. ufbxi_for_ptr_list(ufbx_cache_file, p_cache, uc->scene.cache_files) {
  20299. ufbx_cache_file *cache = *p_cache;
  20300. ufbxi_external_file *file = ufbxi_find_external_file(files, num_files,
  20301. UFBXI_EXTERNAL_FILE_GEOMETRY_CACHE, cache->filename.data);
  20302. if (file && file->data) {
  20303. cache->external_cache = (ufbx_geometry_cache*)file->data;
  20304. }
  20305. }
  20306. // Patch the geometry deformers
  20307. ufbxi_for_ptr_list(ufbx_cache_deformer, p_deformer, uc->scene.cache_deformers) {
  20308. ufbx_cache_deformer *deformer = *p_deformer;
  20309. if (!deformer->file || !deformer->file->external_cache) continue;
  20310. ufbx_geometry_cache *cache = deformer->file->external_cache;
  20311. deformer->external_cache = cache;
  20312. // HACK: It seems like channels may be connected even if the name is wrong
  20313. // and they work when exporting from Marvelous to Maya...
  20314. if (cache->channels.count == 1) {
  20315. deformer->external_channel = &cache->channels.data[0];
  20316. } else {
  20317. ufbx_string channel = deformer->channel;
  20318. size_t ix = SIZE_MAX;
  20319. ufbxi_macro_lower_bound_eq(ufbx_cache_channel, 16, &ix, cache->channels.data, 0, cache->channels.count,
  20320. ( ufbxi_str_less(a->name, channel) ), ( a->name.data == channel.data ));
  20321. if (ix != SIZE_MAX) {
  20322. deformer->external_channel = &cache->channels.data[ix];
  20323. }
  20324. }
  20325. }
  20326. return 1;
  20327. }
  20328. static ufbxi_noinline void ufbxi_transform_to_axes(ufbxi_context *uc, ufbx_coordinate_axes dst_axes)
  20329. {
  20330. if (!ufbx_coordinate_axes_valid(uc->scene.settings.axes)) return;
  20331. if (!ufbxi_axis_matrix(&uc->axis_matrix, uc->scene.settings.axes, dst_axes)) return;
  20332. if (ufbx_matrix_determinant(&uc->axis_matrix) < 0.0f) {
  20333. if (uc->opts.handedness_conversion_axis != UFBX_MIRROR_AXIS_NONE) {
  20334. ufbx_mirror_axis mirror_axis = uc->opts.handedness_conversion_axis;
  20335. uc->mirror_axis = mirror_axis;
  20336. uc->scene.metadata.mirror_axis = uc->mirror_axis;
  20337. ufbxi_mirror_matrix_dst(&uc->axis_matrix, uc->mirror_axis);
  20338. ufbxi_dev_assert(ufbx_matrix_determinant(&uc->axis_matrix) >= 0.0f);
  20339. ufbxi_for_ptr_list(ufbx_node, p_node, uc->scene.nodes) {
  20340. ufbx_node *node = *p_node;
  20341. if (!node->is_root) {
  20342. node->adjust_mirror_axis = mirror_axis;
  20343. }
  20344. }
  20345. }
  20346. }
  20347. if (uc->opts.space_conversion == UFBX_SPACE_CONVERSION_TRANSFORM_ROOT) {
  20348. ufbx_matrix axis_mat = uc->axis_matrix;
  20349. if (!ufbxi_is_transform_identity(&uc->scene.root_node->local_transform)) {
  20350. ufbx_matrix root_mat = ufbx_transform_to_matrix(&uc->scene.root_node->local_transform);
  20351. axis_mat = ufbx_matrix_mul(&root_mat, &axis_mat);
  20352. }
  20353. ufbxi_mirror_matrix(&axis_mat, uc->mirror_axis);
  20354. uc->scene.root_node->local_transform = ufbx_matrix_to_transform(&axis_mat);
  20355. uc->scene.root_node->node_to_parent = axis_mat;
  20356. }
  20357. }
  20358. static ufbxi_noinline int ufbxi_scale_units(ufbxi_context *uc, ufbx_real target_meters)
  20359. {
  20360. if (uc->scene.settings.unit_meters <= 0.0f) return 1;
  20361. target_meters = ufbxi_round_if_near(ufbxi_pow10_targets, ufbxi_arraycount(ufbxi_pow10_targets), target_meters);
  20362. ufbx_real ratio = uc->scene.settings.unit_meters / target_meters;
  20363. ratio = ufbxi_round_if_near(ufbxi_pow10_targets, ufbxi_arraycount(ufbxi_pow10_targets), ratio);
  20364. if (ratio == 1.0f) return 1;
  20365. uc->unit_scale = ratio;
  20366. if (uc->opts.space_conversion == UFBX_SPACE_CONVERSION_TRANSFORM_ROOT) {
  20367. uc->scene.root_node->local_transform.scale.x *= ratio;
  20368. uc->scene.root_node->local_transform.scale.y *= ratio;
  20369. uc->scene.root_node->local_transform.scale.z *= ratio;
  20370. uc->scene.root_node->node_to_parent.m00 *= ratio;
  20371. uc->scene.root_node->node_to_parent.m01 *= ratio;
  20372. uc->scene.root_node->node_to_parent.m02 *= ratio;
  20373. uc->scene.root_node->node_to_parent.m10 *= ratio;
  20374. uc->scene.root_node->node_to_parent.m11 *= ratio;
  20375. uc->scene.root_node->node_to_parent.m12 *= ratio;
  20376. uc->scene.root_node->node_to_parent.m20 *= ratio;
  20377. uc->scene.root_node->node_to_parent.m21 *= ratio;
  20378. uc->scene.root_node->node_to_parent.m22 *= ratio;
  20379. }
  20380. return 1;
  20381. }
  20382. // -- Curve evaluation
  20383. static ufbxi_forceinline double ufbxi_find_cubic_bezier_t(double p1, double p2, double x0)
  20384. {
  20385. double p1_3 = p1 * 3.0, p2_3 = p2 * 3.0;
  20386. double a = p1_3 - p2_3 + 1.0;
  20387. double b = p2_3 - p1_3 - p1_3;
  20388. double c = p1_3;
  20389. double a_3 = 3.0*a, b_2 = 2.0*b;
  20390. double t = x0;
  20391. double x1, t2, t3;
  20392. // Manually unroll three iterations of Newton-Rhapson, this is enough
  20393. // for most tangents
  20394. t2 = t*t; t3 = t2*t; x1 = a*t3 + b*t2 + c*t - x0;
  20395. t -= x1 / (a_3*t2 + b_2*t + c);
  20396. t2 = t*t; t3 = t2*t; x1 = a*t3 + b*t2 + c*t - x0;
  20397. t -= x1 / (a_3*t2 + b_2*t + c);
  20398. t2 = t*t; t3 = t2*t; x1 = a*t3 + b*t2 + c*t - x0;
  20399. t -= x1 / (a_3*t2 + b_2*t + c);
  20400. // 4 ULP from 1.0
  20401. const double eps = 8.881784197001252e-16;
  20402. if (ufbx_fabs(x1) <= eps) return t;
  20403. // Perform more iterations until we reach desired accuracy
  20404. for (size_t i = 0; i < 4; i++) {
  20405. t2 = t*t; t3 = t2*t; x1 = a*t3 + b*t2 + c*t - x0;
  20406. t -= x1 / (a_3*t2 + b_2*t + c);
  20407. t2 = t*t; t3 = t2*t; x1 = a*t3 + b*t2 + c*t - x0;
  20408. t -= x1 / (a_3*t2 + b_2*t + c);
  20409. if (ufbx_fabs(x1) <= eps) return t;
  20410. }
  20411. return t;
  20412. }
  20413. ufbxi_nodiscard static ufbxi_noinline int ufbxi_evaluate_skinning(ufbx_scene *scene, ufbx_error *error, ufbxi_buf *buf_result, ufbxi_buf *buf_tmp,
  20414. double time, bool load_caches, ufbx_geometry_cache_data_opts *cache_opts)
  20415. {
  20416. #if UFBXI_FEATURE_SKINNING_EVALUATION
  20417. size_t max_skinned_indices = 0;
  20418. ufbxi_for_ptr_list(ufbx_mesh, p_mesh, scene->meshes) {
  20419. ufbx_mesh *mesh = *p_mesh;
  20420. if (mesh->blend_deformers.count == 0 && mesh->skin_deformers.count == 0 && (mesh->cache_deformers.count == 0 || !load_caches)) continue;
  20421. max_skinned_indices = ufbxi_max_sz(max_skinned_indices, mesh->num_indices);
  20422. }
  20423. ufbx_topo_edge *topo = ufbxi_push(buf_tmp, ufbx_topo_edge, max_skinned_indices);
  20424. ufbxi_check_err(error, topo);
  20425. ufbxi_for_ptr_list(ufbx_mesh, p_mesh, scene->meshes) {
  20426. ufbx_mesh *mesh = *p_mesh;
  20427. if (mesh->blend_deformers.count == 0 && mesh->skin_deformers.count == 0 && (mesh->cache_deformers.count == 0 || !load_caches)) continue;
  20428. if (mesh->num_vertices == 0) continue;
  20429. size_t num_vertices = mesh->num_vertices;
  20430. ufbx_vec3 *result_pos = ufbxi_push(buf_result, ufbx_vec3, num_vertices + 1);
  20431. ufbxi_check_err(error, result_pos);
  20432. result_pos[0] = ufbx_zero_vec3;
  20433. result_pos++;
  20434. bool cached_position = false, cached_normals = false;
  20435. if (load_caches && mesh->cache_deformers.count > 0) {
  20436. ufbxi_for_ptr_list(ufbx_cache_deformer, p_cache, mesh->cache_deformers) {
  20437. ufbx_cache_channel *channel = (*p_cache)->external_channel;
  20438. if (!channel) continue;
  20439. if ((channel->interpretation == UFBX_CACHE_INTERPRETATION_VERTEX_POSITION || channel->interpretation == UFBX_CACHE_INTERPRETATION_POINTS) && !cached_position) {
  20440. size_t num_read = ufbx_sample_geometry_cache_vec3(channel, time, result_pos, num_vertices, cache_opts);
  20441. if (num_read == num_vertices) {
  20442. mesh->skinned_is_local = true;
  20443. cached_position = true;
  20444. }
  20445. } else if (channel->interpretation == UFBX_CACHE_INTERPRETATION_VERTEX_NORMAL && !cached_normals) {
  20446. // TODO: Is this right at all?
  20447. size_t num_normals = mesh->skinned_normal.values.count;
  20448. ufbx_vec3 *normal_data = ufbxi_push(buf_result, ufbx_vec3, num_normals + 1);
  20449. ufbxi_check_err(error, normal_data);
  20450. normal_data[0] = ufbx_zero_vec3;
  20451. normal_data++;
  20452. size_t num_read = ufbx_sample_geometry_cache_vec3(channel, time, normal_data, num_normals, cache_opts);
  20453. if (num_read == num_normals) {
  20454. cached_normals = true;
  20455. mesh->skinned_normal.values.data = normal_data;
  20456. }
  20457. }
  20458. }
  20459. }
  20460. if (!cached_position) {
  20461. memcpy(result_pos, mesh->vertices.data, num_vertices * sizeof(ufbx_vec3));
  20462. ufbxi_for_ptr_list(ufbx_blend_deformer, p_blend, mesh->blend_deformers) {
  20463. ufbx_add_blend_vertex_offsets(*p_blend, result_pos, num_vertices, 1.0f);
  20464. }
  20465. // TODO: What should we do about multiple skins??
  20466. if (mesh->skin_deformers.count > 0) {
  20467. ufbx_matrix *fallback = mesh->instances.count > 0 ? &mesh->instances.data[0]->geometry_to_world : NULL;
  20468. ufbx_skin_deformer *skin = mesh->skin_deformers.data[0];
  20469. for (size_t i = 0; i < num_vertices; i++) {
  20470. ufbx_matrix mat = ufbx_get_skin_vertex_matrix(skin, i, fallback);
  20471. result_pos[i] = ufbx_transform_position(&mat, result_pos[i]);
  20472. }
  20473. mesh->skinned_is_local = false;
  20474. }
  20475. }
  20476. mesh->skinned_position.values.data = result_pos;
  20477. if (!cached_normals) {
  20478. size_t num_indices = mesh->num_indices;
  20479. uint32_t *normal_indices = ufbxi_push(buf_result, uint32_t, num_indices);
  20480. ufbxi_check_err(error, normal_indices);
  20481. ufbx_compute_topology(mesh, topo, num_indices);
  20482. size_t num_normals = ufbx_generate_normal_mapping(mesh, topo, num_indices, normal_indices, num_indices, false);
  20483. if (num_normals == mesh->num_vertices) {
  20484. mesh->skinned_normal.unique_per_vertex = true;
  20485. }
  20486. ufbx_vec3 *normal_data = ufbxi_push(buf_result, ufbx_vec3, num_normals + 1);
  20487. ufbxi_check_err(error, normal_data);
  20488. normal_data[0] = ufbx_zero_vec3;
  20489. normal_data++;
  20490. ufbx_compute_normals(mesh, &mesh->skinned_position, normal_indices, num_indices, normal_data, num_normals);
  20491. mesh->generated_normals = true;
  20492. mesh->skinned_normal.exists = true;
  20493. mesh->skinned_normal.values.data = normal_data;
  20494. mesh->skinned_normal.values.count = num_normals;
  20495. mesh->skinned_normal.indices.data = normal_indices;
  20496. mesh->skinned_normal.indices.count = num_indices;
  20497. mesh->skinned_normal.value_reals = 3;
  20498. }
  20499. }
  20500. return 1;
  20501. #else
  20502. ufbxi_fmt_err_info(error, "UFBX_ENABLE_SKINNING_EVALUATION");
  20503. ufbxi_report_err_msg(error, "UFBXI_FEATURE_SKINNING_EVALUATION", "Feature disabled");
  20504. return 0;
  20505. #endif
  20506. }
  20507. ufbxi_nodiscard static ufbxi_noinline int ufbxi_fixup_opts_string(ufbxi_context *uc, ufbx_string *str, bool push)
  20508. {
  20509. if (str->length > 0) {
  20510. if (str->length == SIZE_MAX) {
  20511. str->length = str->data ? strlen(str->data) : 0;
  20512. }
  20513. if (push) {
  20514. ufbxi_check(ufbxi_push_string_place_str(&uc->string_pool, str, false));
  20515. }
  20516. } else {
  20517. str->data = ufbxi_empty_char;
  20518. }
  20519. return 1;
  20520. }
  20521. ufbxi_nodiscard static ufbxi_noinline int ufbxi_resolve_warning_elements(ufbxi_context *uc)
  20522. {
  20523. size_t num_elements = uc->tmp_element_id.num_items;
  20524. uint32_t *element_ids = ufbxi_push_pop(&uc->tmp, &uc->tmp_element_id, uint32_t, num_elements);
  20525. ufbxi_check(element_ids);
  20526. ufbxi_for_list(ufbx_warning, warning, uc->scene.metadata.warnings) {
  20527. uint32_t element_id = warning->element_id;
  20528. // Decode `element_id`, see HACK(warning-element) in `ufbxi_vwarnf_imp()` for the encoding.
  20529. if ((element_id & 0x80000000u) != 0 && element_id != ~0u) {
  20530. warning->element_id = element_ids[element_id & ~0x80000000u];
  20531. }
  20532. }
  20533. return 1;
  20534. }
  20535. ufbxi_nodiscard static ufbxi_noinline int ufbxi_load_imp(ufbxi_context *uc)
  20536. {
  20537. // Check for deferred failure
  20538. if (uc->deferred_failure) return 0;
  20539. ufbxi_check(uc->opts.path_separator >= 0x20 && uc->opts.path_separator <= 0x7e);
  20540. ufbxi_check(ufbxi_fixup_opts_string(uc, &uc->opts.filename, false));
  20541. ufbxi_check(ufbxi_fixup_opts_string(uc, &uc->opts.obj_mtl_path, true));
  20542. ufbxi_check(ufbxi_fixup_opts_string(uc, &uc->opts.geometry_transform_helper_name, true));
  20543. ufbxi_check(ufbxi_fixup_opts_string(uc, &uc->opts.scale_helper_name, true));
  20544. ufbxi_check(ufbxi_thread_pool_init(&uc->thread_pool, &uc->error, &uc->ator_tmp, &uc->opts.thread_opts));
  20545. if (!uc->opts.allow_unsafe) {
  20546. ufbxi_check_msg(uc->opts.index_error_handling != UFBX_INDEX_ERROR_HANDLING_UNSAFE_IGNORE, "Unsafe options");
  20547. ufbxi_check_msg(uc->opts.unicode_error_handling != UFBX_UNICODE_ERROR_HANDLING_UNSAFE_IGNORE, "Unsafe options");
  20548. } else {
  20549. uc->scene.metadata.is_unsafe = true;
  20550. }
  20551. if (uc->opts.index_error_handling == UFBX_INDEX_ERROR_HANDLING_NO_INDEX) {
  20552. uc->scene.metadata.may_contain_no_index = true;
  20553. }
  20554. uc->retain_mesh_parts = !uc->opts.ignore_geometry && !uc->opts.skip_mesh_parts;
  20555. uc->scene.metadata.may_contain_missing_vertex_position = uc->opts.allow_missing_vertex_position;
  20556. uc->scene.metadata.may_contain_broken_elements = uc->opts.connect_broken_elements;
  20557. uc->scene.metadata.creator.data = ufbxi_empty_char;
  20558. uc->unit_scale = 1.0f;
  20559. if (uc->data == NULL) {
  20560. ufbxi_dev_assert(uc->data_begin == NULL);
  20561. uc->data_begin = uc->data = ufbxi_zero_size_buffer;
  20562. }
  20563. uc->retain_vertex_w = (uc->opts.retain_dom || uc->opts.retain_vertex_attrib_w) && !uc->opts.ignore_geometry;
  20564. ufbxi_check(ufbxi_load_strings(uc));
  20565. ufbxi_check(ufbxi_load_maps(uc));
  20566. ufbxi_check(ufbxi_determine_format(uc));
  20567. ufbx_file_format format = uc->scene.metadata.file_format;
  20568. if (format == UFBX_FILE_FORMAT_FBX) {
  20569. ufbxi_check(ufbxi_begin_parse(uc));
  20570. if (uc->version < 6000) {
  20571. ufbxi_check(ufbxi_read_legacy_root(uc));
  20572. } else {
  20573. ufbxi_check(ufbxi_read_root(uc));
  20574. }
  20575. ufbxi_update_scene_metadata(&uc->scene.metadata);
  20576. ufbxi_check(ufbxi_init_file_paths(uc));
  20577. } else if (format == UFBX_FILE_FORMAT_OBJ) {
  20578. ufbxi_check(ufbxi_obj_load(uc));
  20579. ufbxi_update_scene_metadata(&uc->scene.metadata);
  20580. } else if (format == UFBX_FILE_FORMAT_MTL) {
  20581. ufbxi_check(ufbxi_mtl_load(uc));
  20582. ufbxi_update_scene_metadata(&uc->scene.metadata);
  20583. }
  20584. // Fake DOM root if necessary
  20585. if (uc->opts.retain_dom && !uc->scene.dom_root) {
  20586. ufbx_dom_node *dom_root = ufbxi_push_zero(&uc->result, ufbx_dom_node, 1);
  20587. ufbxi_check(dom_root);
  20588. dom_root->name.data = ufbxi_empty_char;
  20589. uc->scene.dom_root = dom_root;
  20590. }
  20591. ufbxi_check(ufbxi_pre_finalize_scene(uc));
  20592. // We can free `tmp_parse` already here as all parsing is done by now.
  20593. ufbxi_buf_free(&uc->tmp_parse);
  20594. ufbxi_check(ufbxi_finalize_scene(uc));
  20595. ufbxi_update_scene_settings(&uc->scene.settings);
  20596. if (uc->scene.metadata.file_format == UFBX_FILE_FORMAT_OBJ) {
  20597. ufbxi_update_scene_settings_obj(uc);
  20598. }
  20599. // Axis conversion
  20600. if (ufbx_coordinate_axes_valid(uc->opts.target_axes)) {
  20601. ufbxi_transform_to_axes(uc, uc->opts.target_axes);
  20602. }
  20603. // Unit conversion
  20604. if (uc->opts.target_unit_meters > 0.0f) {
  20605. ufbxi_check(ufbxi_scale_units(uc, uc->opts.target_unit_meters));
  20606. }
  20607. // TODO: This could be done in evaluate as well with refactoring
  20608. ufbxi_update_adjust_transforms(uc, &uc->scene);
  20609. ufbxi_check(ufbxi_modify_geometry(uc));
  20610. ufbxi_postprocess_scene(uc);
  20611. ufbxi_update_scene(&uc->scene, true, NULL, 0);
  20612. // Force a non-NULL anim pointer
  20613. if (!uc->scene.anim) {
  20614. uc->scene.anim = ufbxi_push_zero(&uc->result, ufbx_anim, 1);
  20615. }
  20616. if (uc->opts.load_external_files) {
  20617. ufbxi_check(ufbxi_load_external_files(uc));
  20618. }
  20619. // Evaluate skinning if requested
  20620. if (uc->opts.evaluate_skinning) {
  20621. ufbx_geometry_cache_data_opts cache_opts = { 0 };
  20622. cache_opts.open_file_cb = uc->opts.open_file_cb;
  20623. ufbxi_check(ufbxi_evaluate_skinning(&uc->scene, &uc->error, &uc->result, &uc->tmp,
  20624. 0.0, uc->opts.load_external_files && uc->opts.evaluate_caches, &cache_opts));
  20625. }
  20626. // Pop warnings to metadata
  20627. ufbxi_check(ufbxi_pop_warnings(&uc->warnings, &uc->scene.metadata.warnings, uc->scene.metadata.has_warning));
  20628. ufbxi_check(ufbxi_resolve_warning_elements(uc));
  20629. // Copy local data to the scene
  20630. uc->scene.metadata.version = uc->version;
  20631. uc->scene.metadata.ascii = uc->from_ascii;
  20632. uc->scene.metadata.big_endian = uc->file_big_endian;
  20633. uc->scene.metadata.geometry_ignored = uc->opts.ignore_geometry;
  20634. uc->scene.metadata.animation_ignored = uc->opts.ignore_animation;
  20635. uc->scene.metadata.embedded_ignored = uc->opts.ignore_embedded;
  20636. // Retain the scene, this must be the final allocation as we copy
  20637. // `ator_result` to `ufbx_scene_imp`.
  20638. ufbxi_scene_imp *imp = ufbxi_push(&uc->result, ufbxi_scene_imp, 1);
  20639. ufbxi_check(imp);
  20640. ufbxi_init_ref(&imp->refcount, UFBXI_SCENE_IMP_MAGIC, NULL);
  20641. imp->magic = UFBXI_SCENE_IMP_MAGIC;
  20642. imp->scene = uc->scene;
  20643. imp->refcount.ator = uc->ator_result;
  20644. imp->refcount.ator.error = NULL;
  20645. // Copy retained buffers and translate the allocator struct to the one
  20646. // contained within `ufbxi_scene_imp`
  20647. imp->refcount.buf = uc->result;
  20648. imp->refcount.buf.ator = &imp->refcount.ator;
  20649. imp->string_buf = uc->string_pool.buf;
  20650. imp->string_buf.ator = &imp->refcount.ator;
  20651. imp->scene.metadata.result_memory_used = imp->refcount.ator.current_size;
  20652. imp->scene.metadata.temp_memory_used = uc->ator_tmp.current_size;
  20653. imp->scene.metadata.result_allocs = imp->refcount.ator.num_allocs;
  20654. imp->scene.metadata.temp_allocs = uc->ator_tmp.num_allocs;
  20655. ufbxi_for_ptr_list(ufbx_element, p_elem, imp->scene.elements) {
  20656. (*p_elem)->scene = &imp->scene;
  20657. }
  20658. uc->scene_imp = imp;
  20659. return 1;
  20660. }
  20661. static ufbxi_noinline void ufbxi_free_temp(ufbxi_context *uc)
  20662. {
  20663. ufbxi_thread_pool_free(&uc->thread_pool);
  20664. ufbxi_string_pool_temp_free(&uc->string_pool);
  20665. ufbxi_buf_free(&uc->warnings.tmp_stack);
  20666. ufbxi_map_free(&uc->prop_type_map);
  20667. ufbxi_map_free(&uc->fbx_id_map);
  20668. ufbxi_map_free(&uc->texture_file_map);
  20669. ufbxi_map_free(&uc->anim_stack_map);
  20670. ufbxi_map_free(&uc->fbx_attr_map);
  20671. ufbxi_map_free(&uc->node_prop_set);
  20672. ufbxi_map_free(&uc->dom_node_map);
  20673. ufbxi_buf_free(&uc->tmp);
  20674. ufbxi_buf_free(&uc->tmp_parse);
  20675. for (size_t i = 0; i < UFBX_THREAD_GROUP_COUNT; i++) {
  20676. ufbxi_buf_free(&uc->tmp_thread_parse[i]);
  20677. }
  20678. ufbxi_buf_free(&uc->tmp_stack);
  20679. ufbxi_buf_free(&uc->tmp_connections);
  20680. ufbxi_buf_free(&uc->tmp_node_ids);
  20681. ufbxi_buf_free(&uc->tmp_elements);
  20682. ufbxi_buf_free(&uc->tmp_element_offsets);
  20683. ufbxi_buf_free(&uc->tmp_element_fbx_ids);
  20684. ufbxi_buf_free(&uc->tmp_element_ptrs);
  20685. for (size_t i = 0; i < UFBX_ELEMENT_TYPE_COUNT; i++) {
  20686. ufbxi_buf_free(&uc->tmp_typed_element_offsets[i]);
  20687. }
  20688. ufbxi_buf_free(&uc->tmp_mesh_textures);
  20689. ufbxi_buf_free(&uc->tmp_full_weights);
  20690. ufbxi_buf_free(&uc->tmp_dom_nodes);
  20691. ufbxi_buf_free(&uc->tmp_element_id);
  20692. ufbxi_buf_free(&uc->tmp_ascii_spans);
  20693. ufbxi_free(&uc->ator_tmp, ufbxi_node, uc->top_nodes, uc->top_nodes_cap);
  20694. ufbxi_free(&uc->ator_tmp, void*, uc->element_extra_arr, uc->element_extra_cap);
  20695. ufbxi_free(&uc->ator_tmp, char, uc->ascii.token.str_data, uc->ascii.token.str_cap);
  20696. ufbxi_free(&uc->ator_tmp, char, uc->ascii.prev_token.str_data, uc->ascii.prev_token.str_cap);
  20697. ufbxi_free(&uc->ator_tmp, char, uc->read_buffer, uc->read_buffer_size);
  20698. ufbxi_free(&uc->ator_tmp, char, uc->tmp_arr, uc->tmp_arr_size);
  20699. ufbxi_free(&uc->ator_tmp, char, uc->swap_arr, uc->swap_arr_size);
  20700. ufbxi_obj_free(uc);
  20701. ufbxi_free_ator(&uc->ator_tmp);
  20702. }
  20703. static ufbxi_noinline void ufbxi_free_result(ufbxi_context *uc)
  20704. {
  20705. ufbxi_buf_free(&uc->result);
  20706. ufbxi_buf_free(&uc->string_pool.buf);
  20707. ufbxi_free_ator(&uc->ator_result);
  20708. }
  20709. static ufbxi_noinline ufbx_scene *ufbxi_load(ufbxi_context *uc, const ufbx_load_opts *user_opts, ufbx_error *p_error)
  20710. {
  20711. // Test endianness
  20712. {
  20713. uint8_t buf[2];
  20714. uint16_t val = 0xbbaa;
  20715. memcpy(buf, &val, 2);
  20716. uc->local_big_endian = buf[0] == 0xbb;
  20717. }
  20718. uc->double_parse_flags = ufbxi_parse_double_init_flags();
  20719. if (user_opts) {
  20720. uc->opts = *user_opts;
  20721. } else {
  20722. memset(&uc->opts, 0, sizeof(uc->opts));
  20723. }
  20724. if (uc->opts.file_size_estimate) {
  20725. uc->progress_bytes_total = uc->opts.file_size_estimate;
  20726. }
  20727. if (uc->opts.ignore_all_content) {
  20728. uc->opts.ignore_geometry = true;
  20729. uc->opts.ignore_animation = true;
  20730. uc->opts.ignore_embedded = true;
  20731. }
  20732. ufbx_inflate_retain inflate_retain;
  20733. inflate_retain.initialized = false;
  20734. ufbxi_init_ator(&uc->error, &uc->ator_tmp, &uc->opts.temp_allocator, "temp");
  20735. ufbxi_init_ator(&uc->error, &uc->ator_result, &uc->opts.result_allocator, "result");
  20736. if (uc->opts.read_buffer_size == 0) {
  20737. uc->opts.read_buffer_size = 0x4000;
  20738. }
  20739. if (uc->opts.file_format_lookahead == 0) {
  20740. uc->opts.file_format_lookahead = 0x4000;
  20741. } else if (uc->opts.file_format_lookahead < UFBXI_MIN_FILE_FORMAT_LOOKAHEAD) {
  20742. uc->opts.file_format_lookahead = UFBXI_MIN_FILE_FORMAT_LOOKAHEAD;
  20743. }
  20744. if (!uc->opts.path_separator) {
  20745. uc->opts.path_separator = UFBX_PATH_SEPARATOR;
  20746. }
  20747. if (!uc->opts.progress_cb.fn || uc->opts.progress_interval_hint >= SIZE_MAX) {
  20748. uc->progress_interval = SIZE_MAX;
  20749. } else if (uc->opts.progress_interval_hint > 0) {
  20750. uc->progress_interval = (size_t)uc->opts.progress_interval_hint;
  20751. } else {
  20752. uc->progress_interval = 0x4000;
  20753. }
  20754. if (!uc->opts.open_file_cb.fn) {
  20755. uc->opts.open_file_cb.fn = &ufbx_default_open_file;
  20756. }
  20757. if (!uc->opts.thread_opts.memory_limit) {
  20758. uc->opts.thread_opts.memory_limit = 32*1024*1024;
  20759. }
  20760. uc->string_pool.error = &uc->error;
  20761. ufbxi_map_init(&uc->string_pool.map, &uc->ator_tmp, &ufbxi_map_cmp_string, NULL);
  20762. uc->string_pool.buf.ator = &uc->ator_result;
  20763. uc->string_pool.buf.unordered = true;
  20764. uc->string_pool.initial_size = 1024;
  20765. uc->string_pool.error_handling = uc->opts.unicode_error_handling;
  20766. ufbxi_map_init(&uc->prop_type_map, &uc->ator_tmp, &ufbxi_map_cmp_const_char_ptr, NULL);
  20767. ufbxi_map_init(&uc->fbx_id_map, &uc->ator_tmp, &ufbxi_map_cmp_uint64, NULL);
  20768. ufbxi_map_init(&uc->texture_file_map, &uc->ator_tmp, &ufbxi_map_cmp_const_char_ptr, NULL);
  20769. ufbxi_map_init(&uc->anim_stack_map, &uc->ator_tmp, &ufbxi_map_cmp_const_char_ptr, NULL);
  20770. ufbxi_map_init(&uc->fbx_attr_map, &uc->ator_tmp, &ufbxi_map_cmp_uint64, NULL);
  20771. ufbxi_map_init(&uc->node_prop_set, &uc->ator_tmp, &ufbxi_map_cmp_const_char_ptr, NULL);
  20772. ufbxi_map_init(&uc->dom_node_map, &uc->ator_tmp, &ufbxi_map_cmp_uintptr, NULL);
  20773. uc->tmp.ator = &uc->ator_tmp;
  20774. uc->tmp_parse.ator = &uc->ator_tmp;
  20775. uc->tmp_stack.ator = &uc->ator_tmp;
  20776. uc->tmp_connections.ator = &uc->ator_tmp;
  20777. uc->tmp_node_ids.ator = &uc->ator_tmp;
  20778. uc->tmp_elements.ator = &uc->ator_tmp;
  20779. uc->tmp_element_offsets.ator = &uc->ator_tmp;
  20780. uc->tmp_element_fbx_ids.ator = &uc->ator_tmp;
  20781. uc->tmp_element_ptrs.ator = &uc->ator_tmp;
  20782. for (size_t i = 0; i < UFBX_ELEMENT_TYPE_COUNT; i++) {
  20783. uc->tmp_typed_element_offsets[i].ator = &uc->ator_tmp;
  20784. }
  20785. uc->tmp_mesh_textures.ator = &uc->ator_tmp;
  20786. uc->tmp_full_weights.ator = &uc->ator_tmp;
  20787. uc->tmp_dom_nodes.ator = &uc->ator_tmp;
  20788. uc->tmp_element_id.ator = &uc->ator_tmp;
  20789. uc->tmp_ascii_spans.ator = &uc->ator_tmp;
  20790. for (size_t i = 0; i < UFBX_THREAD_GROUP_COUNT; i++) {
  20791. uc->tmp_thread_parse[i].ator = &uc->ator_tmp;
  20792. uc->tmp_thread_parse[i].unordered = true;
  20793. uc->tmp_thread_parse[i].clearable = true;
  20794. }
  20795. uc->result.ator = &uc->ator_result;
  20796. uc->tmp.unordered = true;
  20797. uc->tmp_parse.unordered = true;
  20798. uc->tmp_parse.clearable = true;
  20799. uc->result.unordered = true;
  20800. uc->warnings.error = &uc->error;
  20801. uc->warnings.result = &uc->result;
  20802. uc->warnings.tmp_stack.ator = &uc->ator_tmp;
  20803. uc->string_pool.warnings = &uc->warnings;
  20804. // Set zero size `swap_arr` to a non-NULL buffer so we can tell the difference between empty
  20805. // array and an allocation failure.
  20806. uc->swap_arr = (char*)ufbxi_zero_size_buffer;
  20807. // NOTE: Though `inflate_retain` leaks out of the scope we don't use it outside this function.
  20808. // cppcheck-suppress autoVariables
  20809. uc->inflate_retain = &inflate_retain;
  20810. int ok = ufbxi_load_imp(uc);
  20811. ufbxi_free_temp(uc);
  20812. if (uc->close_fn) {
  20813. uc->close_fn(uc->read_user);
  20814. }
  20815. if (ok) {
  20816. if (p_error) {
  20817. ufbxi_clear_error(p_error);
  20818. }
  20819. return &uc->scene_imp->scene;
  20820. } else {
  20821. ufbxi_fix_error_type(&uc->error, "Failed to load");
  20822. if (p_error) *p_error = uc->error;
  20823. ufbxi_free_result(uc);
  20824. return NULL;
  20825. }
  20826. }
  20827. static ufbxi_noinline ufbx_scene *ufbxi_load_not_found(const char *filename, size_t filename_len, ufbx_error *p_error)
  20828. {
  20829. ufbxi_context uc = { UFBX_ERROR_NONE };
  20830. ufbxi_set_err_info(&uc.error, filename, filename_len);
  20831. ufbxi_report_err_msg(&uc.error, "File not found", "File not found");
  20832. uc.deferred_failure = true;
  20833. return ufbxi_load(&uc, NULL, p_error);
  20834. }
  20835. // -- Animation evaluation
  20836. static ufbxi_forceinline bool ufbxi_override_less_than_prop(const ufbx_prop_override *over, uint32_t element_id, const ufbx_prop *prop)
  20837. {
  20838. if (over->element_id != element_id) return over->element_id < element_id;
  20839. if (over->_internal_key != prop->_internal_key) return over->_internal_key < prop->_internal_key;
  20840. return strcmp(over->prop_name.data, prop->name.data);
  20841. }
  20842. static ufbxi_forceinline bool ufbxi_override_equals_to_prop(const ufbx_prop_override *over, uint32_t element_id, const ufbx_prop *prop)
  20843. {
  20844. if (over->element_id != element_id) return false;
  20845. if (over->_internal_key != prop->_internal_key) return false;
  20846. return !strcmp(over->prop_name.data, prop->name.data);
  20847. }
  20848. static ufbxi_noinline bool ufbxi_find_prop_override(const ufbx_prop_override_list *overrides, uint32_t element_id, ufbx_prop *prop)
  20849. {
  20850. size_t ix = SIZE_MAX;
  20851. ufbxi_macro_lower_bound_eq(ufbx_prop_override, 16, &ix, overrides->data, 0, overrides->count,
  20852. ( ufbxi_override_less_than_prop(a, element_id, prop) ),
  20853. ( ufbxi_override_equals_to_prop(a, element_id, prop) ));
  20854. if (ix != SIZE_MAX) {
  20855. const ufbx_prop_override *over = &overrides->data[ix];
  20856. const uint32_t clear_flags = UFBX_PROP_FLAG_NO_VALUE | UFBX_PROP_FLAG_NOT_FOUND;
  20857. prop->flags = (ufbx_prop_flags)(((uint32_t)prop->flags & ~clear_flags) | UFBX_PROP_FLAG_OVERRIDDEN);
  20858. prop->value_vec4 = over->value;
  20859. prop->value_real_arr[3] = 0.0f;
  20860. prop->value_int = over->value_int;
  20861. prop->value_str = over->value_str;
  20862. prop->value_blob.data = prop->value_str.data;
  20863. prop->value_blob.size = prop->value_str.length;
  20864. return true;
  20865. } else {
  20866. return false;
  20867. }
  20868. }
  20869. static ufbxi_noinline ufbx_prop_override_list ufbxi_find_element_prop_overrides(const ufbx_prop_override_list *overrides, uint32_t element_id)
  20870. {
  20871. size_t begin = overrides->count, end = begin;
  20872. ufbxi_macro_lower_bound_eq(ufbx_prop_override, 32, &begin, overrides->data, 0, overrides->count,
  20873. (a->element_id < element_id),
  20874. (a->element_id == element_id));
  20875. ufbxi_macro_upper_bound_eq(ufbx_prop_override, 32, &end, overrides->data, begin, overrides->count,
  20876. (a->element_id == element_id));
  20877. ufbx_prop_override_list result = { overrides->data + begin, end - begin };
  20878. return result;
  20879. }
  20880. typedef struct ufbxi_anim_layer_combine_ctx {
  20881. const ufbx_anim *anim;
  20882. const ufbx_element *element;
  20883. double time;
  20884. ufbx_rotation_order rotation_order;
  20885. bool has_rotation_order;
  20886. } ufbxi_anim_layer_combine_ctx;
  20887. static ufbxi_noinline double ufbxi_pow_abs(double v, double e)
  20888. {
  20889. if (e <= 0.0) return 1.0;
  20890. if (e >= 1.0) return v;
  20891. double sign = v < 0.0 ? -1.0 : 1.0;
  20892. return sign * ufbx_pow(v * sign, e);
  20893. }
  20894. // Recursion is limited by the fact that we recurse only when the property name is "Lcl Rotation"
  20895. // and when recursing we always evaluate the property "RotationOrder"
  20896. static ufbxi_noinline void ufbxi_combine_anim_layer(ufbxi_anim_layer_combine_ctx *ctx, ufbx_anim_layer *layer, ufbx_real weight, const char *prop_name, ufbx_vec3 *result, const ufbx_vec3 *value)
  20897. ufbxi_recursive_function_void(ufbxi_combine_anim_layer, (ctx, layer, weight, prop_name, result, value), 2,
  20898. (ufbxi_anim_layer_combine_ctx *ctx, ufbx_anim_layer *layer, ufbx_real weight, const char *prop_name, ufbx_vec3 *result, const ufbx_vec3 *value))
  20899. {
  20900. if (layer->compose_rotation && layer->blended && prop_name == ufbxi_Lcl_Rotation && !ctx->has_rotation_order) {
  20901. ufbx_prop rp = ufbx_evaluate_prop_len(ctx->anim, ctx->element, ufbxi_RotationOrder, sizeof(ufbxi_RotationOrder) - 1, ctx->time);
  20902. // NOTE: Defaults to 0 (UFBX_ROTATION_XYZ) gracefully if property is not found
  20903. if (rp.value_int >= 0 && rp.value_int <= UFBX_ROTATION_ORDER_SPHERIC) {
  20904. ctx->rotation_order = (ufbx_rotation_order)rp.value_int;
  20905. } else {
  20906. ctx->rotation_order = UFBX_ROTATION_ORDER_XYZ;
  20907. }
  20908. ctx->has_rotation_order = true;
  20909. }
  20910. if (layer->additive) {
  20911. if (layer->compose_scale && prop_name == ufbxi_Lcl_Scaling) {
  20912. result->x *= (ufbx_real)ufbxi_pow_abs(value->x, weight);
  20913. result->y *= (ufbx_real)ufbxi_pow_abs(value->y, weight);
  20914. result->z *= (ufbx_real)ufbxi_pow_abs(value->z, weight);
  20915. } else if (layer->compose_rotation && prop_name == ufbxi_Lcl_Rotation) {
  20916. ufbx_quat a = ufbx_euler_to_quat(*result, ctx->rotation_order);
  20917. ufbx_quat b = ufbx_euler_to_quat(*value, ctx->rotation_order);
  20918. b = ufbx_quat_slerp(ufbx_identity_quat, b, weight);
  20919. ufbx_quat res = ufbxi_mul_quat(a, b);
  20920. *result = ufbx_quat_to_euler(res, ctx->rotation_order);
  20921. } else {
  20922. result->x += value->x * weight;
  20923. result->y += value->y * weight;
  20924. result->z += value->z * weight;
  20925. }
  20926. } else if (layer->blended) {
  20927. ufbx_real res_weight = 1.0f - weight;
  20928. if (layer->compose_scale && prop_name == ufbxi_Lcl_Scaling) {
  20929. result->x = (ufbx_real)(ufbxi_pow_abs(result->x, res_weight) * ufbxi_pow_abs(value->x, weight));
  20930. result->y = (ufbx_real)(ufbxi_pow_abs(result->y, res_weight) * ufbxi_pow_abs(value->y, weight));
  20931. result->z = (ufbx_real)(ufbxi_pow_abs(result->z, res_weight) * ufbxi_pow_abs(value->z, weight));
  20932. } else if (layer->compose_rotation && prop_name == ufbxi_Lcl_Rotation) {
  20933. ufbx_quat a = ufbx_euler_to_quat(*result, ctx->rotation_order);
  20934. ufbx_quat b = ufbx_euler_to_quat(*value, ctx->rotation_order);
  20935. ufbx_quat res = ufbx_quat_slerp(a, b, weight);
  20936. *result = ufbx_quat_to_euler(res, ctx->rotation_order);
  20937. } else {
  20938. result->x = result->x * res_weight + value->x * weight;
  20939. result->y = result->y * res_weight + value->y * weight;
  20940. result->z = result->z * res_weight + value->z * weight;
  20941. }
  20942. } else {
  20943. *result = *value;
  20944. }
  20945. }
  20946. static ufbxi_forceinline bool ufbxi_anim_layer_might_contain_id(const ufbx_anim_layer *layer, uint32_t id)
  20947. {
  20948. uint32_t id_mask = ufbxi_arraycount(layer->_element_id_bitmask) - 1;
  20949. bool ok = id - layer->_min_element_id <= (layer->_max_element_id - layer->_min_element_id);
  20950. ok &= (layer->_element_id_bitmask[(id >> 5) & id_mask] & (1u << (id & 31))) != 0;
  20951. return ok;
  20952. }
  20953. static ufbxi_noinline void ufbxi_evaluate_props(const ufbx_anim *anim, const ufbx_element *element, double time, ufbx_prop *props, size_t num_props)
  20954. {
  20955. ufbxi_anim_layer_combine_ctx combine_ctx = { anim, element, time };
  20956. uint32_t element_id = element->element_id;
  20957. size_t num_layers = anim->layers.count;
  20958. for (size_t layer_ix = 0; layer_ix < num_layers; layer_ix++) {
  20959. ufbx_anim_layer *layer = anim->layers.data[layer_ix];
  20960. if (!ufbxi_anim_layer_might_contain_id(layer, element_id)) continue;
  20961. // Find the weight for the current layer
  20962. // TODO: Should this be searched from multiple layers?
  20963. ufbx_real weight = layer_ix < anim->override_layer_weights.count ? anim->override_layer_weights.data[layer_ix] : layer->weight;
  20964. if (layer->weight_is_animated && layer->blended) {
  20965. ufbx_anim_prop *weight_aprop = ufbxi_find_anim_prop_start(layer, &layer->element);
  20966. if (weight_aprop) {
  20967. weight = ufbx_evaluate_anim_value_real(weight_aprop->anim_value, time) / (ufbx_real)100.0;
  20968. if (weight < 0.0f) weight = 0.0f;
  20969. if (weight > 0.99999f) weight = 1.0f;
  20970. }
  20971. }
  20972. ufbx_anim_prop *aprop = ufbxi_find_anim_prop_start(layer, element);
  20973. if (!aprop) continue;
  20974. for (size_t i = 0; i < num_props; i++) {
  20975. ufbx_prop *prop = &props[i];
  20976. // Don't evaluate on top of overridden properties
  20977. if ((prop->flags & UFBX_PROP_FLAG_OVERRIDDEN) != 0) continue;
  20978. // Connections override animation by default
  20979. if ((prop->flags & UFBX_PROP_FLAG_CONNECTED) != 0 && !anim->ignore_connections) continue;
  20980. // Skip until we reach `aprop >= prop`
  20981. // NOTE: No need to check for end as `anim_props` is terminated with a NULL sentinel.
  20982. while (aprop->element == element && aprop->_internal_key < prop->_internal_key) aprop++;
  20983. if (aprop->prop_name.data != prop->name.data) {
  20984. while (aprop->element == element && strcmp(aprop->prop_name.data, prop->name.data) < 0) aprop++;
  20985. }
  20986. // TODO: Should we skip the blending for the first layer _per property_
  20987. // This could be done by having `UFBX_PROP_FLAG_ANIMATION_EVALUATED`
  20988. // that gets set for the first layer of animation that is applied.
  20989. if (aprop->prop_name.data == prop->name.data) {
  20990. ufbx_vec3 v = ufbx_evaluate_anim_value_vec3(aprop->anim_value, time);
  20991. if (layer_ix == 0) {
  20992. prop->value_vec3 = v;
  20993. } else {
  20994. ufbxi_combine_anim_layer(&combine_ctx, layer, weight, prop->name.data, &prop->value_vec3, &v);
  20995. }
  20996. }
  20997. }
  20998. }
  20999. ufbxi_for(ufbx_prop, prop, props, num_props) {
  21000. if (prop->flags & UFBX_PROP_FLAG_OVERRIDDEN) continue;
  21001. prop->value_int = ufbxi_f64_to_i64(prop->value_real);
  21002. }
  21003. }
  21004. // Recursion limited by not calling `ufbx_evaluate_prop_len()` with a connected property,
  21005. // meaning it will never call `ufbxi_evaluate_connected_prop()` again indirectly.
  21006. static ufbxi_noinline void ufbxi_evaluate_connected_prop(ufbx_prop *prop, const ufbx_anim *anim, const ufbx_element *element, const char *name, double time)
  21007. ufbxi_recursive_function_void(ufbxi_evaluate_connected_prop, (prop, anim, element, name, time), 3,
  21008. (ufbx_prop *prop, const ufbx_anim *anim, const ufbx_element *element, const char *name, double time))
  21009. {
  21010. ufbx_connection *conn = ufbxi_find_prop_connection(element, name);
  21011. for (size_t i = 0; i < 1000 && conn; i++) {
  21012. ufbx_connection *next_conn = ufbxi_find_prop_connection(conn->src, conn->src_prop.data);
  21013. if (!next_conn) break;
  21014. conn = next_conn;
  21015. }
  21016. // Found a non-cyclic connection
  21017. if (conn && !ufbxi_find_prop_connection(conn->src, conn->src_prop.data)) {
  21018. ufbx_prop ep = ufbx_evaluate_prop_len(anim, conn->src, conn->src_prop.data, conn->src_prop.length, time);
  21019. prop->value_vec4 = ep.value_vec4;
  21020. prop->value_int = ep.value_int;
  21021. prop->value_str = ep.value_str;
  21022. prop->value_blob = ep.value_blob;
  21023. } else {
  21024. // Connection not found, maybe it's animated?
  21025. prop->flags = (ufbx_prop_flags)((uint32_t)prop->flags & ~(uint32_t)UFBX_PROP_FLAG_CONNECTED);
  21026. }
  21027. }
  21028. typedef struct {
  21029. const ufbx_prop *prop, *prop_end;
  21030. const ufbx_prop_override *over, *over_end;
  21031. ufbx_prop tmp;
  21032. } ufbxi_prop_iter;
  21033. static ufbxi_noinline void ufbxi_init_prop_iter_slow(ufbxi_prop_iter *iter, const ufbx_anim *anim, const ufbx_element *element)
  21034. {
  21035. iter->prop = element->props.props.data;
  21036. iter->prop_end = element->props.props.data + element->props.props.count;
  21037. ufbx_prop_override_list over = ufbxi_find_element_prop_overrides(&anim->prop_overrides, element->element_id);
  21038. iter->over = over.data;
  21039. iter->over_end = over.data + over.count;
  21040. if (over.count > 0) {
  21041. memset(&iter->tmp, 0, sizeof(ufbx_prop));
  21042. }
  21043. }
  21044. static ufbxi_forceinline void ufbxi_init_prop_iter(ufbxi_prop_iter *iter, const ufbx_anim *anim, const ufbx_element *element)
  21045. {
  21046. iter->prop = element->props.props.data;
  21047. iter->prop_end = ufbxi_add_ptr(element->props.props.data, element->props.props.count);
  21048. iter->over = iter->over_end = NULL;
  21049. if (anim->prop_overrides.count > 0) {
  21050. ufbxi_init_prop_iter_slow(iter, anim, element);
  21051. }
  21052. }
  21053. static ufbxi_noinline const ufbx_prop *ufbxi_next_prop_slow(ufbxi_prop_iter *iter)
  21054. {
  21055. const ufbx_prop *prop = iter->prop;
  21056. const ufbx_prop_override *over = iter->over;
  21057. if (prop == iter->prop_end && over == iter->over_end) return NULL;
  21058. // We can use `UINT32_MAX` as a termianting key (aka prefix) as prop names must
  21059. // be valid UTF-8 and the byte sequence "\xff\xff\xff\xff" is not valid.
  21060. uint32_t prop_key = prop != iter->prop_end ? prop->_internal_key : UINT32_MAX;
  21061. uint32_t over_key = over != iter->over_end ? over->_internal_key : UINT32_MAX;
  21062. int cmp = 0;
  21063. if (prop_key != over_key) {
  21064. cmp = prop_key < over_key ? -1 : 1;
  21065. } else {
  21066. cmp = strcmp(prop->name.data, over->prop_name.data);
  21067. }
  21068. if (cmp >= 0) {
  21069. ufbx_prop *dst = &iter->tmp;
  21070. dst->name = over->prop_name;
  21071. dst->_internal_key = over->_internal_key;
  21072. dst->type = UFBX_PROP_UNKNOWN;
  21073. dst->flags = UFBX_PROP_FLAG_OVERRIDDEN;
  21074. dst->value_str = over->value_str;
  21075. dst->value_blob.data = dst->value_str.data;
  21076. dst->value_blob.size = dst->value_str.length;
  21077. dst->value_int = over->value_int;
  21078. dst->value_vec4 = over->value;
  21079. iter->over = over + 1;
  21080. if (cmp == 0) {
  21081. iter->prop = prop + 1;
  21082. }
  21083. return dst;
  21084. } else {
  21085. iter->prop = prop + 1;
  21086. return prop;
  21087. }
  21088. }
  21089. static ufbxi_forceinline const ufbx_prop *ufbxi_next_prop(ufbxi_prop_iter *iter)
  21090. {
  21091. if (iter->over == iter->over_end) {
  21092. if (iter->prop == iter->prop_end) return NULL;
  21093. return iter->prop++;
  21094. } else {
  21095. return ufbxi_next_prop_slow(iter);
  21096. }
  21097. }
  21098. static ufbxi_noinline ufbx_props ufbxi_evaluate_selected_props(const ufbx_anim *anim, const ufbx_element *element, double time, ufbx_prop *props, const char *const *prop_names, size_t max_props)
  21099. {
  21100. const char *name = prop_names[0];
  21101. uint32_t key = ufbxi_get_name_key_c(name);
  21102. size_t num_props = 0;
  21103. #if defined(UFBX_REGRESSION)
  21104. for (size_t i = 1; i < max_props; i++) {
  21105. ufbx_assert(strcmp(prop_names[i - 1], prop_names[i]) < 0);
  21106. }
  21107. #endif
  21108. size_t name_ix = 0;
  21109. ufbxi_prop_iter iter; // ufbxi_uninit
  21110. ufbxi_init_prop_iter(&iter, anim, element);
  21111. const ufbx_prop *prop = NULL;
  21112. while ((prop = ufbxi_next_prop(&iter)) != NULL) {
  21113. while (name_ix < max_props) {
  21114. if (key > prop->_internal_key) break;
  21115. if (name == prop->name.data) {
  21116. if ((prop->flags & UFBX_PROP_FLAG_CONNECTED) != 0 && !anim->ignore_connections) {
  21117. ufbx_prop *dst = &props[num_props++];
  21118. *dst = *prop;
  21119. ufbxi_evaluate_connected_prop(dst, anim, element, name, time);
  21120. } else if ((prop->flags & (UFBX_PROP_FLAG_ANIMATED|UFBX_PROP_FLAG_OVERRIDDEN)) != 0) {
  21121. props[num_props++] = *prop;
  21122. }
  21123. break;
  21124. } else if (strcmp(name, prop->name.data) < 0) {
  21125. name_ix++;
  21126. if (name_ix < max_props) {
  21127. name = prop_names[name_ix];
  21128. key = ufbxi_get_name_key_c(name);
  21129. }
  21130. } else {
  21131. break;
  21132. }
  21133. }
  21134. }
  21135. ufbxi_evaluate_props(anim, element, time, props, num_props);
  21136. ufbx_props prop_list;
  21137. prop_list.props.data = props;
  21138. prop_list.props.count = prop_list.num_animated = num_props;
  21139. prop_list.defaults = (ufbx_props*)&element->props;
  21140. return prop_list;
  21141. }
  21142. #if UFBXI_FEATURE_SCENE_EVALUATION
  21143. typedef struct {
  21144. char *src_element;
  21145. char *dst_element;
  21146. ufbxi_scene_imp *src_imp;
  21147. ufbx_scene src_scene;
  21148. ufbx_evaluate_opts opts;
  21149. ufbx_anim *anim;
  21150. double time;
  21151. ufbx_error error;
  21152. // Allocators
  21153. ufbxi_allocator ator_result;
  21154. ufbxi_allocator ator_tmp;
  21155. ufbxi_buf result;
  21156. ufbxi_buf tmp;
  21157. ufbx_scene scene;
  21158. ufbxi_scene_imp *scene_imp;
  21159. } ufbxi_eval_context;
  21160. static ufbxi_forceinline ufbx_element *ufbxi_translate_element(ufbxi_eval_context *ec, void *elem)
  21161. {
  21162. return elem ? (ufbx_element*)(ec->dst_element + ((char*)elem - ec->src_element)) : NULL;
  21163. }
  21164. ufbxi_nodiscard static ufbxi_noinline int ufbxi_translate_element_list(ufbxi_eval_context *ec, void *p_list)
  21165. {
  21166. ufbx_element_list *list = (ufbx_element_list*)p_list;
  21167. size_t count = list->count;
  21168. ufbx_element **src = list->data;
  21169. ufbx_element **dst = ufbxi_push(&ec->result, ufbx_element*, count);
  21170. ufbxi_check_err(&ec->error, dst);
  21171. list->data = dst;
  21172. for (size_t i = 0; i < count; i++) {
  21173. dst[i] = ufbxi_translate_element(ec, src[i]);
  21174. }
  21175. return 1;
  21176. }
  21177. static ufbxi_noinline void ufbxi_translate_maps(ufbxi_eval_context *ec, ufbx_material_map *maps, size_t count)
  21178. {
  21179. ufbxi_nounroll ufbxi_for(ufbx_material_map, map, maps, count) {
  21180. map->texture = (ufbx_texture*)ufbxi_translate_element(ec, map->texture);
  21181. }
  21182. }
  21183. ufbxi_nodiscard static ufbxi_noinline int ufbxi_translate_anim(ufbxi_eval_context *ec, ufbx_anim **p_anim)
  21184. {
  21185. ufbx_anim *anim = ufbxi_push_copy(&ec->result, ufbx_anim, 1, *p_anim);
  21186. ufbxi_check_err(&ec->error, anim);
  21187. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &anim->layers));
  21188. *p_anim = anim;
  21189. return 1;
  21190. }
  21191. ufbxi_nodiscard static ufbxi_noinline int ufbxi_evaluate_imp(ufbxi_eval_context *ec)
  21192. {
  21193. ec->scene = ec->src_scene;
  21194. size_t num_elements = ec->scene.elements.count;
  21195. char *element_data = (char*)ufbxi_push(&ec->result, uint64_t, ec->scene.metadata.element_buffer_size/8);
  21196. ufbxi_check_err(&ec->error, element_data);
  21197. ec->scene.elements.data = ufbxi_push(&ec->result, ufbx_element*, num_elements);
  21198. ufbxi_check_err(&ec->error, ec->scene.elements.data);
  21199. ec->src_element = (char*)ec->src_scene.elements.data[0];
  21200. ec->dst_element = element_data;
  21201. for (size_t i = 0; i < UFBX_ELEMENT_TYPE_COUNT; i++) {
  21202. ec->scene.elements_by_type[i].data = ufbxi_push(&ec->result, ufbx_element*, ec->scene.elements_by_type[i].count);
  21203. ufbxi_check_err(&ec->error, ec->scene.elements_by_type[i].data);
  21204. }
  21205. size_t num_connections = ec->scene.connections_dst.count;
  21206. ec->scene.connections_src.data = ufbxi_push(&ec->result, ufbx_connection, num_connections);
  21207. ec->scene.connections_dst.data = ufbxi_push(&ec->result, ufbx_connection, num_connections);
  21208. ufbxi_check_err(&ec->error, ec->scene.connections_src.data);
  21209. ufbxi_check_err(&ec->error, ec->scene.connections_dst.data);
  21210. for (size_t i = 0; i < num_connections; i++) {
  21211. ufbx_connection *src = &ec->scene.connections_src.data[i];
  21212. ufbx_connection *dst = &ec->scene.connections_dst.data[i];
  21213. *src = ec->src_scene.connections_src.data[i];
  21214. *dst = ec->src_scene.connections_dst.data[i];
  21215. src->src = ufbxi_translate_element(ec, src->src);
  21216. src->dst = ufbxi_translate_element(ec, src->dst);
  21217. dst->src = ufbxi_translate_element(ec, dst->src);
  21218. dst->dst = ufbxi_translate_element(ec, dst->dst);
  21219. }
  21220. ec->scene.elements_by_name.data = ufbxi_push(&ec->result, ufbx_name_element, num_elements);
  21221. ufbxi_check_err(&ec->error, ec->scene.elements_by_name.data);
  21222. ec->scene.root_node = (ufbx_node*)ufbxi_translate_element(ec, ec->scene.root_node);
  21223. ufbxi_check_err(&ec->error, ufbxi_translate_anim(ec, &ec->scene.anim));
  21224. for (size_t i = 0; i < num_elements; i++) {
  21225. ufbx_element *src = ec->src_scene.elements.data[i];
  21226. ufbx_element *dst = ufbxi_translate_element(ec, src);
  21227. size_t size = ufbx_element_type_size[src->type];
  21228. ufbx_assert(size > 0);
  21229. memcpy(dst, src, size);
  21230. ec->scene.elements.data[i] = dst;
  21231. ec->scene.elements_by_type[src->type].data[src->typed_id] = dst;
  21232. dst->connections_src.data = ec->scene.connections_src.data + (dst->connections_src.data - ec->src_scene.connections_src.data);
  21233. dst->connections_dst.data = ec->scene.connections_dst.data + (dst->connections_dst.data - ec->src_scene.connections_dst.data);
  21234. if (dst->instances.count > 0) {
  21235. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &dst->instances));
  21236. }
  21237. ufbx_name_element named = ec->src_scene.elements_by_name.data[i];
  21238. named.element = ufbxi_translate_element(ec, named.element);
  21239. ec->scene.elements_by_name.data[i] = named;
  21240. }
  21241. ufbxi_for_ptr_list(ufbx_node, p_node, ec->scene.nodes) {
  21242. ufbx_node *node = *p_node;
  21243. node->parent = (ufbx_node*)ufbxi_translate_element(ec, node->parent);
  21244. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &node->children));
  21245. node->attrib = ufbxi_translate_element(ec, node->attrib);
  21246. node->mesh = (ufbx_mesh*)ufbxi_translate_element(ec, node->mesh);
  21247. node->light = (ufbx_light*)ufbxi_translate_element(ec, node->light);
  21248. node->camera = (ufbx_camera*)ufbxi_translate_element(ec, node->camera);
  21249. node->bone = (ufbx_bone*)ufbxi_translate_element(ec, node->bone);
  21250. node->inherit_scale_node = (ufbx_node*)ufbxi_translate_element(ec, node->inherit_scale_node);
  21251. node->scale_helper = (ufbx_node*)ufbxi_translate_element(ec, node->scale_helper);
  21252. node->bind_pose = (ufbx_pose*)ufbxi_translate_element(ec, node->bind_pose);
  21253. if (node->all_attribs.count > 1) {
  21254. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &node->all_attribs));
  21255. } else if (node->all_attribs.count == 1) {
  21256. node->all_attribs.data = &node->attrib;
  21257. }
  21258. node->geometry_transform_helper = (ufbx_node*)ufbxi_translate_element(ec, node->geometry_transform_helper);
  21259. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &node->materials));
  21260. }
  21261. ufbxi_for_ptr_list(ufbx_mesh, p_mesh, ec->scene.meshes) {
  21262. ufbx_mesh *mesh = *p_mesh;
  21263. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &mesh->materials));
  21264. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &mesh->skin_deformers));
  21265. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &mesh->blend_deformers));
  21266. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &mesh->cache_deformers));
  21267. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &mesh->all_deformers));
  21268. }
  21269. ufbxi_for_ptr_list(ufbx_stereo_camera, p_stereo, ec->scene.stereo_cameras) {
  21270. ufbx_stereo_camera *stereo = *p_stereo;
  21271. stereo->left = (ufbx_camera*)ufbxi_translate_element(ec, stereo->left);
  21272. stereo->right = (ufbx_camera*)ufbxi_translate_element(ec, stereo->right);
  21273. }
  21274. ufbxi_for_ptr_list(ufbx_skin_deformer, p_skin, ec->scene.skin_deformers) {
  21275. ufbx_skin_deformer *skin = *p_skin;
  21276. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &skin->clusters));
  21277. }
  21278. ufbxi_for_ptr_list(ufbx_skin_cluster, p_cluster, ec->scene.skin_clusters) {
  21279. ufbx_skin_cluster *cluster = *p_cluster;
  21280. cluster->bone_node = (ufbx_node*)ufbxi_translate_element(ec, cluster->bone_node);
  21281. }
  21282. ufbxi_for_ptr_list(ufbx_blend_deformer, p_blend, ec->scene.blend_deformers) {
  21283. ufbx_blend_deformer *blend = *p_blend;
  21284. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &blend->channels));
  21285. }
  21286. ufbxi_for_ptr_list(ufbx_blend_channel, p_chan, ec->scene.blend_channels) {
  21287. ufbx_blend_channel *chan = *p_chan;
  21288. ufbx_blend_keyframe *keys = ufbxi_push(&ec->result, ufbx_blend_keyframe, chan->keyframes.count);
  21289. ufbxi_check_err(&ec->error, keys);
  21290. for (size_t i = 0; i < chan->keyframes.count; i++) {
  21291. keys[i] = chan->keyframes.data[i];
  21292. keys[i].shape = (ufbx_blend_shape*)ufbxi_translate_element(ec, keys[i].shape);
  21293. }
  21294. chan->keyframes.data = keys;
  21295. chan->target_shape = (ufbx_blend_shape*)ufbxi_translate_element(ec, chan->target_shape);
  21296. }
  21297. ufbxi_for_ptr_list(ufbx_cache_deformer, p_deformer, ec->scene.cache_deformers) {
  21298. ufbx_cache_deformer *deformer = *p_deformer;
  21299. deformer->file = (ufbx_cache_file*)ufbxi_translate_element(ec, deformer->file);
  21300. }
  21301. ufbxi_for_ptr_list(ufbx_material, p_material, ec->scene.materials) {
  21302. ufbx_material *material = *p_material;
  21303. material->shader = (ufbx_shader*)ufbxi_translate_element(ec, material->shader);
  21304. ufbxi_translate_maps(ec, material->fbx.maps, UFBX_MATERIAL_FBX_MAP_COUNT);
  21305. ufbxi_translate_maps(ec, material->pbr.maps, UFBX_MATERIAL_PBR_MAP_COUNT);
  21306. ufbx_material_texture *textures = ufbxi_push(&ec->result, ufbx_material_texture, material->textures.count);
  21307. ufbxi_check_err(&ec->error, textures);
  21308. for (size_t i = 0; i < material->textures.count; i++) {
  21309. textures[i] = material->textures.data[i];
  21310. textures[i].texture = (ufbx_texture*)ufbxi_translate_element(ec, textures[i].texture);
  21311. }
  21312. material->textures.data = textures;
  21313. }
  21314. ufbxi_for_ptr_list(ufbx_texture, p_texture, ec->scene.textures) {
  21315. ufbx_texture *texture = *p_texture;
  21316. texture->video = (ufbx_video*)ufbxi_translate_element(ec, texture->video);
  21317. ufbx_texture_layer *layers = ufbxi_push(&ec->result, ufbx_texture_layer, texture->layers.count);
  21318. ufbxi_check_err(&ec->error, layers);
  21319. for (size_t i = 0; i < texture->layers.count; i++) {
  21320. layers[i] = texture->layers.data[i];
  21321. layers[i].texture = (ufbx_texture*)ufbxi_translate_element(ec, layers[i].texture);
  21322. }
  21323. texture->layers.data = layers;
  21324. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &texture->file_textures));
  21325. if (texture->shader) {
  21326. ufbx_shader_texture *shader = texture->shader;
  21327. shader = ufbxi_push_copy(&ec->result, ufbx_shader_texture, 1, shader);
  21328. ufbxi_check_err(&ec->error, shader);
  21329. texture->shader = shader;
  21330. ufbx_shader_texture_input *inputs = ufbxi_push_copy(&ec->result, ufbx_shader_texture_input, shader->inputs.count, shader->inputs.data);
  21331. ufbxi_check_err(&ec->error, inputs);
  21332. shader->inputs.data = inputs;
  21333. }
  21334. }
  21335. ufbxi_for_ptr_list(ufbx_shader, p_shader, ec->scene.shaders) {
  21336. ufbx_shader *shader = *p_shader;
  21337. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &shader->bindings));
  21338. }
  21339. ufbxi_for_ptr_list(ufbx_display_layer, p_layer, ec->scene.display_layers) {
  21340. ufbx_display_layer *layer = *p_layer;
  21341. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &layer->nodes));
  21342. }
  21343. ufbxi_for_ptr_list(ufbx_selection_set, p_set, ec->scene.selection_sets) {
  21344. ufbx_selection_set *set = *p_set;
  21345. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &set->nodes));
  21346. }
  21347. ufbxi_for_ptr_list(ufbx_selection_node, p_node, ec->scene.selection_nodes) {
  21348. ufbx_selection_node *node = *p_node;
  21349. node->target_node = (ufbx_node*)ufbxi_translate_element(ec, node->target_node);
  21350. node->target_mesh = (ufbx_mesh*)ufbxi_translate_element(ec, node->target_mesh);
  21351. }
  21352. ufbxi_for_ptr_list(ufbx_constraint, p_constraint, ec->scene.constraints) {
  21353. ufbx_constraint *constraint = *p_constraint;
  21354. constraint->node = (ufbx_node*)ufbxi_translate_element(ec, constraint->node);
  21355. constraint->aim_up_node = (ufbx_node*)ufbxi_translate_element(ec, constraint->aim_up_node);
  21356. constraint->ik_effector = (ufbx_node*)ufbxi_translate_element(ec, constraint->ik_effector);
  21357. constraint->ik_end_node = (ufbx_node*)ufbxi_translate_element(ec, constraint->ik_end_node);
  21358. ufbx_constraint_target *targets = ufbxi_push(&ec->result, ufbx_constraint_target, constraint->targets.count);
  21359. ufbxi_check_err(&ec->error, targets);
  21360. for (size_t i = 0; i < constraint->targets.count; i++) {
  21361. targets[i] = constraint->targets.data[i];
  21362. targets[i].node = (ufbx_node*)ufbxi_translate_element(ec, targets[i].node);
  21363. }
  21364. constraint->targets.data = targets;
  21365. }
  21366. ufbxi_for_ptr_list(ufbx_audio_layer, p_layer, ec->scene.audio_layers) {
  21367. ufbx_audio_layer *layer = *p_layer;
  21368. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &layer->clips));
  21369. }
  21370. ufbxi_for_ptr_list(ufbx_anim_stack, p_stack, ec->scene.anim_stacks) {
  21371. ufbx_anim_stack *stack = *p_stack;
  21372. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &stack->layers));
  21373. ufbxi_check_err(&ec->error, ufbxi_translate_anim(ec, &stack->anim));
  21374. }
  21375. ufbxi_for_ptr_list(ufbx_anim_layer, p_layer, ec->scene.anim_layers) {
  21376. ufbx_anim_layer *layer = *p_layer;
  21377. ufbxi_check_err(&ec->error, ufbxi_translate_element_list(ec, &layer->anim_values));
  21378. ufbx_anim_prop *props = ufbxi_push(&ec->result, ufbx_anim_prop, layer->anim_props.count + 1);
  21379. ufbxi_check_err(&ec->error, props);
  21380. for (size_t i = 0; i < layer->anim_props.count; i++) {
  21381. props[i] = layer->anim_props.data[i];
  21382. props[i].element = ufbxi_translate_element(ec, props[i].element);
  21383. props[i].anim_value = (ufbx_anim_value*)ufbxi_translate_element(ec, props[i].anim_value);
  21384. }
  21385. // Maintain NULL sentinel
  21386. memset(props + layer->anim_props.count, 0, sizeof(ufbx_anim_prop));
  21387. layer->anim_props.data = props;
  21388. }
  21389. ufbxi_for_ptr_list(ufbx_pose, p_pose, ec->scene.poses) {
  21390. ufbx_pose *pose = *p_pose;
  21391. ufbx_bone_pose *bones = ufbxi_push(&ec->result, ufbx_bone_pose, pose->bone_poses.count);
  21392. ufbxi_check_err(&ec->error, bones);
  21393. for (size_t i = 0; i < pose->bone_poses.count; i++) {
  21394. bones[i] = pose->bone_poses.data[i];
  21395. bones[i].bone_node = (ufbx_node*)ufbxi_translate_element(ec, bones[i].bone_node);
  21396. }
  21397. pose->bone_poses.data = bones;
  21398. }
  21399. ufbxi_check_err(&ec->error, ufbxi_translate_anim(ec, &ec->anim));
  21400. ufbxi_for_ptr_list(ufbx_anim_value, p_value, ec->scene.anim_values) {
  21401. ufbx_anim_value *value = *p_value;
  21402. value->curves[0] = (ufbx_anim_curve*)ufbxi_translate_element(ec, value->curves[0]);
  21403. value->curves[1] = (ufbx_anim_curve*)ufbxi_translate_element(ec, value->curves[1]);
  21404. value->curves[2] = (ufbx_anim_curve*)ufbxi_translate_element(ec, value->curves[2]);
  21405. }
  21406. ufbx_anim anim = *ec->anim;
  21407. ufbx_prop_override *over = anim.prop_overrides.data, *over_end = ufbxi_add_ptr(over, anim.prop_overrides.count);
  21408. // Evaluate the properties
  21409. ufbxi_for_ptr_list(ufbx_element, p_elem, ec->scene.elements) {
  21410. ufbx_element *elem = *p_elem;
  21411. size_t num_animated = elem->props.num_animated;
  21412. size_t num_override = 0;
  21413. // Setup the overrides for this element if found
  21414. while (over != over_end && over->element_id == elem->element_id) {
  21415. num_override++;
  21416. over++;
  21417. }
  21418. num_animated += num_override;
  21419. if (num_animated == 0) continue;
  21420. anim.prop_overrides.data = ufbxi_sub_ptr(over, num_override);
  21421. anim.prop_overrides.count = num_override;
  21422. ufbx_prop *props = ufbxi_push(&ec->result, ufbx_prop, num_animated);
  21423. ufbxi_check_err(&ec->error, props);
  21424. elem->props = ufbx_evaluate_props(&anim, elem, ec->time, props, num_animated);
  21425. elem->props.defaults = &ec->src_scene.elements.data[elem->element_id]->props;
  21426. }
  21427. // Update all derived values
  21428. ufbxi_update_scene(&ec->scene, false, anim.transform_overrides.data, anim.transform_overrides.count);
  21429. // Evaluate skinning if requested
  21430. if (ec->opts.evaluate_skinning) {
  21431. ufbx_geometry_cache_data_opts cache_opts = { 0 };
  21432. cache_opts.open_file_cb = ec->opts.open_file_cb;
  21433. ufbxi_check_err(&ec->error, ufbxi_evaluate_skinning(&ec->scene, &ec->error, &ec->result, &ec->tmp,
  21434. ec->time, ec->opts.load_external_files && ec->opts.evaluate_caches, &cache_opts));
  21435. }
  21436. // Retain the scene, this must be the final allocation as we copy
  21437. // `ator_result` to `ufbx_scene_imp`.
  21438. ufbxi_scene_imp *imp = ufbxi_push_zero(&ec->result, ufbxi_scene_imp, 1);
  21439. ufbxi_check_err(&ec->error, imp);
  21440. ufbx_assert(ec->src_imp->magic == UFBXI_SCENE_IMP_MAGIC);
  21441. ufbxi_init_ref(&imp->refcount, UFBXI_SCENE_IMP_MAGIC, &ec->src_imp->refcount);
  21442. imp->magic = UFBXI_SCENE_IMP_MAGIC;
  21443. imp->scene = ec->scene;
  21444. imp->refcount.ator = ec->ator_result;
  21445. imp->refcount.ator.error = NULL;
  21446. // Copy retained buffers and translate the allocator struct to the one
  21447. // contained within `ufbxi_scene_imp`
  21448. imp->refcount.buf = ec->result;
  21449. imp->refcount.buf.ator = &imp->refcount.ator;
  21450. imp->scene.metadata.result_memory_used = imp->refcount.ator.current_size;
  21451. imp->scene.metadata.temp_memory_used = ec->ator_tmp.current_size;
  21452. imp->scene.metadata.result_allocs = imp->refcount.ator.num_allocs;
  21453. imp->scene.metadata.temp_allocs = ec->ator_tmp.num_allocs;
  21454. ufbxi_for_ptr_list(ufbx_element, p_elem, imp->scene.elements) {
  21455. (*p_elem)->scene = &imp->scene;
  21456. }
  21457. ec->scene_imp = imp;
  21458. ec->result.ator = &ec->ator_result;
  21459. return 1;
  21460. }
  21461. ufbxi_nodiscard static ufbxi_noinline ufbx_scene *ufbxi_evaluate_scene(ufbxi_eval_context *ec, ufbx_scene *scene, const ufbx_anim *anim, double time, const ufbx_evaluate_opts *user_opts, ufbx_error *p_error)
  21462. {
  21463. if (user_opts) {
  21464. ec->opts = *user_opts;
  21465. } else {
  21466. memset(&ec->opts, 0, sizeof(ec->opts));
  21467. }
  21468. ec->src_imp = ufbxi_get_imp(ufbxi_scene_imp, scene);
  21469. ec->src_scene = *scene;
  21470. ec->anim = anim ? (ufbx_anim*)anim : scene->anim;
  21471. ec->time = time;
  21472. ufbxi_init_ator(&ec->error, &ec->ator_tmp, &ec->opts.temp_allocator, "temp");
  21473. ufbxi_init_ator(&ec->error, &ec->ator_result, &ec->opts.result_allocator, "result");
  21474. ec->result.ator = &ec->ator_result;
  21475. ec->tmp.ator = &ec->ator_tmp;
  21476. ec->result.unordered = true;
  21477. ec->tmp.unordered = true;
  21478. if (ufbxi_evaluate_imp(ec)) {
  21479. ufbxi_buf_free(&ec->tmp);
  21480. ufbxi_free_ator(&ec->ator_tmp);
  21481. if (p_error) {
  21482. ufbxi_clear_error(p_error);
  21483. }
  21484. return &ec->scene_imp->scene;
  21485. } else {
  21486. ufbxi_fix_error_type(&ec->error, "Failed to evaluate");
  21487. if (p_error) *p_error = ec->error;
  21488. ufbxi_buf_free(&ec->tmp);
  21489. ufbxi_buf_free(&ec->result);
  21490. ufbxi_free_ator(&ec->ator_tmp);
  21491. ufbxi_free_ator(&ec->ator_result);
  21492. return NULL;
  21493. }
  21494. }
  21495. #endif
  21496. typedef struct {
  21497. ufbx_error error;
  21498. ufbxi_allocator ator_result;
  21499. ufbxi_buf result;
  21500. const ufbx_scene *scene;
  21501. ufbx_anim_opts opts;
  21502. ufbx_anim anim;
  21503. ufbxi_anim_imp *imp;
  21504. } ufbxi_create_anim_context;
  21505. ufbxi_nodiscard static ufbxi_noinline int ufbxi_check_string(ufbx_error *error, ufbx_string *dst, const ufbx_string *src)
  21506. {
  21507. size_t length = src->length != SIZE_MAX ? src->length : strlen(src->data);
  21508. const char *data = length != 0 ? src->data : ufbxi_empty_char;
  21509. if (length > 0) {
  21510. size_t valid_length = ufbxi_utf8_valid_length(data, length);
  21511. ufbxi_check_err_msg(error, valid_length == length, "Invalid UTF-8");
  21512. }
  21513. dst->data = data;
  21514. dst->length = length;
  21515. return 1;
  21516. }
  21517. ufbxi_nodiscard static ufbxi_noinline int ufbxi_push_anim_string(ufbxi_create_anim_context *ac, ufbx_string *str)
  21518. {
  21519. size_t length = str->length;
  21520. if (length > 0) {
  21521. char *copy = ufbxi_push(&ac->result, char, length + 1);
  21522. ufbxi_check_err(&ac->error, copy);
  21523. memcpy(copy, str->data, length);
  21524. copy[str->length] = '\0';
  21525. str->data = copy;
  21526. } else {
  21527. ufbx_assert(str->data == ufbxi_empty_char);
  21528. }
  21529. return 1;
  21530. }
  21531. static bool ufbxi_prop_override_prop_name_less(void *user, const void *va, const void *vb)
  21532. {
  21533. (void)user;
  21534. const ufbx_prop_override *a = (const ufbx_prop_override*)va, *b = (const ufbx_prop_override*)vb;
  21535. if (a->_internal_key != b->_internal_key) return a->_internal_key < b->_internal_key;
  21536. return ufbxi_str_less(a->prop_name, b->prop_name);
  21537. }
  21538. static bool ufbxi_prop_override_less(void *user, const void *va, const void *vb)
  21539. {
  21540. (void)user;
  21541. const ufbx_prop_override *a = (const ufbx_prop_override*)va, *b = (const ufbx_prop_override*)vb;
  21542. if (a->element_id != b->element_id) return a->element_id < b->element_id;
  21543. if (a->_internal_key != b->_internal_key) return a->_internal_key < b->_internal_key;
  21544. return strcmp(a->prop_name.data, b->prop_name.data) < 0;
  21545. }
  21546. static int ufbxi_cmp_transform_override(const void *va, const void *vb)
  21547. {
  21548. const ufbx_transform_override *a = (const ufbx_transform_override*)va, *b = (const ufbx_transform_override*)vb;
  21549. if (a->node_id != b->node_id) return a->node_id < b->node_id ? -1 : 1;
  21550. return 0;
  21551. }
  21552. ufbxi_nodiscard static ufbxi_noinline int ufbxi_create_anim_imp(ufbxi_create_anim_context *ac)
  21553. {
  21554. const ufbx_scene *scene = ac->scene;
  21555. ufbx_anim *anim = &ac->anim;
  21556. ufbxi_init_ator(&ac->error, &ac->ator_result, &ac->opts.result_allocator, "result");
  21557. ac->result.unordered = true;
  21558. ac->result.ator = &ac->ator_result;
  21559. anim->ignore_connections = ac->opts.ignore_connections;
  21560. anim->custom = true;
  21561. size_t num_layers = ac->opts.layer_ids.count;
  21562. anim->layers.count = num_layers;
  21563. anim->layers.data = ufbxi_push_zero(&ac->result, ufbx_anim_layer*, num_layers);
  21564. ufbxi_check_err(&ac->error, anim->layers.data);
  21565. if (ac->opts.override_layer_weights.count > 0) {
  21566. ufbxi_check_err_msg(&ac->error, ac->opts.override_layer_weights.count == num_layers, "override_layer_weights[] count must match layer_ids[] count");
  21567. anim->override_layer_weights.data = ufbxi_push_copy(&ac->result, ufbx_real, num_layers, ac->opts.override_layer_weights.data);
  21568. ufbxi_check_err(&ac->error, anim->override_layer_weights.data);
  21569. anim->override_layer_weights.count = num_layers;
  21570. }
  21571. for (size_t i = 0; i < num_layers; i++) {
  21572. uint32_t index = ac->opts.layer_ids.data[i];
  21573. ufbxi_check_err_msg(&ac->error, index < scene->anim_layers.count, "layer_ids out of bounds");
  21574. anim->layers.data[i] = ac->scene->anim_layers.data[index];
  21575. }
  21576. ufbx_const_prop_override_desc_list prop_overrides = ac->opts.prop_overrides;
  21577. if (prop_overrides.count > 0) {
  21578. anim->prop_overrides.count = prop_overrides.count;
  21579. anim->prop_overrides.data = ufbxi_push_zero(&ac->result, ufbx_prop_override, prop_overrides.count);
  21580. ufbxi_check_err(&ac->error, anim->prop_overrides.data);
  21581. for (size_t i = 0; i < prop_overrides.count; i++) {
  21582. const ufbx_prop_override_desc *src = &prop_overrides.data[i];
  21583. ufbx_prop_override *dst = &anim->prop_overrides.data[i];
  21584. dst->element_id = src->element_id;
  21585. dst->value = src->value;
  21586. dst->value_int = src->value_int;
  21587. if (dst->value.x != 0.0f && dst->value_int == 0) {
  21588. dst->value_int = (int64_t)dst->value.x;
  21589. } else if (dst->value_int != 0 && dst->value.x == 0.0f) {
  21590. dst->value.x = (ufbx_real)dst->value_int;
  21591. }
  21592. ufbxi_check_err(&ac->error, ufbxi_check_string(&ac->error, &dst->prop_name, &src->prop_name));
  21593. ufbxi_check_err(&ac->error, ufbxi_check_string(&ac->error, &dst->value_str, &src->value_str));
  21594. dst->_internal_key = ufbxi_get_name_key(dst->prop_name.data, dst->prop_name.length);
  21595. }
  21596. // Sort `anim->prop_overrides` first by `prop_name` only so we can deduplicate and
  21597. // convert them to global strings in `ufbxi_strings[]` if possible.
  21598. ufbxi_unstable_sort(anim->prop_overrides.data, anim->prop_overrides.count, sizeof(ufbx_prop_override), &ufbxi_prop_override_prop_name_less, NULL);
  21599. const ufbx_string *global_str = ufbxi_strings, *global_end = global_str + ufbxi_arraycount(ufbxi_strings);
  21600. ufbx_string prev_name = { ufbxi_empty_char };
  21601. ufbxi_for_list(ufbx_prop_override, over, anim->prop_overrides) {
  21602. if (over->value_str.length > 0) {
  21603. ufbxi_check_err(&ac->error, ufbxi_push_anim_string(ac, &over->value_str));
  21604. }
  21605. if (ufbxi_str_equal(over->prop_name, prev_name)) {
  21606. over->prop_name = prev_name;
  21607. continue;
  21608. }
  21609. while (global_str != global_end && ufbxi_str_less(*global_str, over->prop_name)) {
  21610. ++global_str;
  21611. }
  21612. if (global_str != global_end && ufbxi_str_equal(*global_str, over->prop_name)) {
  21613. over->prop_name = *global_str;
  21614. } else {
  21615. ufbxi_check_err(&ac->error, ufbxi_push_anim_string(ac, &over->prop_name));
  21616. }
  21617. prev_name = over->prop_name;
  21618. }
  21619. // Sort `anim->prop_overrides` to the actual order expected by evaluation.
  21620. ufbxi_unstable_sort(anim->prop_overrides.data, anim->prop_overrides.count, sizeof(ufbx_prop_override), &ufbxi_prop_override_less, NULL);
  21621. for (size_t i = 1; i < prop_overrides.count; i++) {
  21622. const ufbx_prop_override *prev = &anim->prop_overrides.data[i - 1];
  21623. const ufbx_prop_override *next = &anim->prop_overrides.data[i];
  21624. if (prev->element_id == next->element_id && prev->prop_name.data == next->prop_name.data) {
  21625. ufbxi_fmt_err_info(&ac->error, "element %u prop \"%s\"", prev->element_id, prev->prop_name.data);
  21626. ufbxi_fail_err_msg(&ac->error, "Duplicate override", "Duplicate override");
  21627. }
  21628. }
  21629. }
  21630. if (ac->opts.transform_overrides.count > 0) {
  21631. anim->transform_overrides.count = ac->opts.transform_overrides.count;
  21632. anim->transform_overrides.data = ufbxi_push_copy(&ac->result, ufbx_transform_override, anim->transform_overrides.count, ac->opts.transform_overrides.data);
  21633. ufbxi_check_err(&ac->error, anim->transform_overrides.data);
  21634. qsort(anim->transform_overrides.data, anim->transform_overrides.count, sizeof(ufbx_transform_override), &ufbxi_cmp_transform_override);
  21635. }
  21636. ac->imp = ufbxi_push(&ac->result, ufbxi_anim_imp, 1);
  21637. ufbxi_check_err(&ac->error, ac->imp);
  21638. ufbxi_init_ref(&ac->imp->refcount, UFBXI_ANIM_IMP_MAGIC, &(ufbxi_get_imp(ufbxi_scene_imp, scene))->refcount);
  21639. ac->imp->magic = UFBXI_ANIM_IMP_MAGIC;
  21640. ac->imp->anim = ac->anim;
  21641. ac->imp->refcount.ator = ac->ator_result;
  21642. ac->imp->refcount.buf = ac->result;
  21643. return 1;
  21644. }
  21645. // -- Animation baking
  21646. typedef struct {
  21647. ufbxi_refcount refcount;
  21648. ufbx_baked_anim bake;
  21649. uint32_t magic;
  21650. } ufbxi_baked_anim_imp;
  21651. #if UFBXI_FEATURE_ANIMATION_BAKING
  21652. typedef struct {
  21653. double time;
  21654. uint32_t flags;
  21655. } ufbxi_bake_time;
  21656. UFBX_LIST_TYPE(ufbxi_bake_time_list, ufbxi_bake_time);
  21657. typedef struct {
  21658. ufbx_error error;
  21659. ufbxi_allocator ator_tmp;
  21660. ufbxi_allocator ator_result;
  21661. ufbxi_buf result;
  21662. ufbxi_buf tmp;
  21663. ufbxi_buf tmp_prop;
  21664. ufbxi_buf tmp_times;
  21665. ufbxi_buf tmp_bake_props;
  21666. ufbxi_buf tmp_nodes;
  21667. ufbxi_buf tmp_elements;
  21668. ufbxi_buf tmp_props;
  21669. ufbxi_buf tmp_bake_stack;
  21670. ufbxi_bake_time_list layer_weight_times;
  21671. ufbx_baked_node **baked_nodes;
  21672. bool *nodes_to_bake;
  21673. const ufbx_scene *scene;
  21674. const ufbx_anim *anim;
  21675. ufbx_bake_opts opts;
  21676. double ktime_offset;
  21677. double time_begin;
  21678. double time_end;
  21679. double time_min;
  21680. double time_max;
  21681. ufbx_baked_anim bake;
  21682. ufbxi_baked_anim_imp *imp;
  21683. } ufbxi_bake_context;
  21684. typedef struct {
  21685. uint32_t sort_id;
  21686. uint32_t element_id;
  21687. const char *prop_name;
  21688. ufbx_anim_value *anim_value;
  21689. } ufbxi_bake_prop;
  21690. static int ufbxi_cmp_bake_prop(const void *va, const void *vb)
  21691. {
  21692. const ufbxi_bake_prop *a = (const ufbxi_bake_prop*)va;
  21693. const ufbxi_bake_prop *b = (const ufbxi_bake_prop*)vb;
  21694. if (a->sort_id != b->sort_id) return a->sort_id < b->sort_id ? -1 : 1;
  21695. if (a->element_id != b->element_id) return a->element_id < b->element_id ? -1 : 1;
  21696. if (a->prop_name != b->prop_name) return strcmp(a->prop_name, b->prop_name);
  21697. return a->anim_value < b->anim_value;
  21698. }
  21699. ufbx_static_assert(bake_step_left, UFBX_BAKED_KEY_STEP_LEFT == 0x1);
  21700. ufbx_static_assert(bake_step_right, UFBX_BAKED_KEY_STEP_RIGHT == 0x2);
  21701. ufbx_static_assert(bake_step_key, UFBX_BAKED_KEY_STEP_KEY == 0x4);
  21702. static ufbxi_forceinline int ufbxi_cmp_bake_time(ufbxi_bake_time a, ufbxi_bake_time b)
  21703. {
  21704. if (a.time != b.time) return a.time < b.time ? -1 : 1;
  21705. // Bit twiddling for a fast sorting of `0x1 (LEFT) < 0x0 < 0x2 (RIGHT)`
  21706. // by `step ^ 1`: `0x0 (LEFT) < 0x1 < 0x3 (RIGHT)`
  21707. uint32_t a_step = a.flags & 0x3, b_step = b.flags & 0x3;
  21708. if (a_step != b_step) return (a_step ^ 0x1) < (b_step ^ 0x1) ? -1 : 1;
  21709. return 0;
  21710. }
  21711. static int ufbxi_cmp_bake_time_fn(const void *va, const void *vb)
  21712. {
  21713. const ufbxi_bake_time a = *(const ufbxi_bake_time*)va;
  21714. const ufbxi_bake_time b = *(const ufbxi_bake_time*)vb;
  21715. return ufbxi_cmp_bake_time(a, b);
  21716. }
  21717. ufbxi_nodiscard static ufbxi_forceinline int ufbxi_bake_push_time(ufbxi_bake_context *bc, double time, uint32_t flags)
  21718. {
  21719. ufbxi_bake_time *p_key = ufbxi_push_fast(&bc->tmp_times, ufbxi_bake_time, 1);
  21720. if (!p_key) return 0;
  21721. p_key->time = time;
  21722. p_key->flags = flags;
  21723. return 1;
  21724. }
  21725. ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_times(ufbxi_bake_context *bc, const ufbx_anim_value *anim_value, bool resample_linear, uint32_t key_flag)
  21726. {
  21727. double sample_rate = bc->opts.resample_rate;
  21728. double min_duration = bc->opts.minimum_sample_rate > 0.0 ? 1.0 / bc->opts.minimum_sample_rate : 0.0;
  21729. for (size_t curve_ix = 0; curve_ix < 3; curve_ix++) {
  21730. ufbx_anim_curve *curve = anim_value->curves[curve_ix];
  21731. if (!curve) continue;
  21732. const ufbx_keyframe *keys = curve->keyframes.data;
  21733. size_t num_keys = curve->keyframes.count;
  21734. for (size_t key_ix = 0; key_ix < num_keys; key_ix++) {
  21735. ufbx_keyframe a = keys[key_ix];
  21736. double a_time = a.time;
  21737. ufbxi_check_err(&bc->error, ufbxi_bake_push_time(bc, a_time, key_flag));
  21738. if (key_ix + 1 >= num_keys) break;
  21739. ufbx_keyframe b = keys[key_ix + 1];
  21740. double b_time = b.time;
  21741. // Skip fully flat sections
  21742. if (a.value == b.value && a.right.dy == 0.0f && b.left.dy == 0.0f) continue;
  21743. if (a.interpolation == UFBX_INTERPOLATION_CONSTANT_PREV) {
  21744. ufbxi_check_err(&bc->error, ufbxi_bake_push_time(bc, b_time, UFBX_BAKED_KEY_STEP_LEFT));
  21745. } else if (a.interpolation == UFBX_INTERPOLATION_CONSTANT_NEXT) {
  21746. ufbxi_check_err(&bc->error, ufbxi_bake_push_time(bc, a_time, UFBX_BAKED_KEY_STEP_RIGHT));
  21747. } else if ((resample_linear || a.interpolation == UFBX_INTERPOLATION_CUBIC) && sample_rate > 0.0) {
  21748. double duration = b_time - a_time;
  21749. if (duration <= min_duration) continue;
  21750. double factor = 1.0;
  21751. while (duration * sample_rate / factor >= (double)bc->opts.max_keyframe_segments) {
  21752. factor *= 2.0;
  21753. }
  21754. double padding = 0.5 / sample_rate;
  21755. double start = ufbx_ceil((a_time + padding) * sample_rate / factor) * factor;
  21756. double stop = b_time - padding;
  21757. for (size_t i = 0; i < bc->opts.max_keyframe_segments; i++) {
  21758. double time = (start + (double)i * factor) / sample_rate;
  21759. if (time >= stop) break;
  21760. ufbxi_check_err(&bc->error, ufbxi_bake_push_time(bc, time, 0));
  21761. }
  21762. }
  21763. }
  21764. }
  21765. return 1;
  21766. }
  21767. static const char *const ufbxi_transform_props[] = {
  21768. ufbxi_Lcl_Translation, ufbxi_Lcl_Rotation, ufbxi_Lcl_Scaling, ufbxi_PreRotation, ufbxi_PostRotation,
  21769. ufbxi_RotationOffset, ufbxi_ScalingOffset, ufbxi_RotationPivot, ufbxi_ScalingPivot, ufbxi_RotationOrder,
  21770. };
  21771. static const char *const ufbxi_complex_translation_props[] = {
  21772. ufbxi_ScalingPivot, ufbxi_RotationPivot, ufbxi_RotationOffset, ufbxi_ScalingOffset,
  21773. };
  21774. static const char *const ufbxi_complex_rotation_props[] = {
  21775. ufbxi_PreRotation, ufbxi_PostRotation, ufbxi_RotationOrder,
  21776. };
  21777. static const char *const ufbxi_complex_rotation_sources[] = {
  21778. ufbxi_Lcl_Rotation, ufbxi_PreRotation, ufbxi_PostRotation, ufbxi_RotationOrder,
  21779. };
  21780. ufbxi_nodiscard static ufbxi_noinline bool ufbxi_in_list(const char *const *items, size_t count, const char *item)
  21781. {
  21782. for (size_t i = 0; i < count; i++) {
  21783. if (items[i] == item) return true;
  21784. }
  21785. return false;
  21786. }
  21787. ufbxi_nodiscard static ufbxi_noinline int ufbxi_finalize_bake_times(ufbxi_bake_context *bc, ufbxi_bake_time_list *p_dst)
  21788. {
  21789. if (bc->layer_weight_times.count > 0) {
  21790. ufbxi_check_err(&bc->error, ufbxi_push_copy(&bc->tmp_times, ufbxi_bake_time, bc->layer_weight_times.count, bc->layer_weight_times.data));
  21791. }
  21792. if (bc->tmp_times.num_items == 0) {
  21793. ufbxi_check_err(&bc->error, ufbxi_bake_push_time(bc, bc->time_begin, 0));
  21794. ufbxi_check_err(&bc->error, ufbxi_bake_push_time(bc, bc->time_end, 0));
  21795. }
  21796. size_t num_times = bc->tmp_times.num_items;
  21797. ufbxi_bake_time *times = ufbxi_push_pop(&bc->tmp_prop, &bc->tmp_times, ufbxi_bake_time, num_times);
  21798. ufbxi_check_err(&bc->error, times);
  21799. // TODO: Something better
  21800. qsort(times, num_times, sizeof(ufbxi_bake_time), &ufbxi_cmp_bake_time_fn);
  21801. // Deduplicate times
  21802. if (num_times > 0) {
  21803. size_t dst = 0;
  21804. ufbxi_bake_time prev = times[0];
  21805. for (size_t src = 1; src < num_times; src++) {
  21806. ufbxi_bake_time next = times[src];
  21807. // Merge keys with the same time and step flags `(0x1, 0x2)`
  21808. if (next.time == prev.time) {
  21809. if (((next.flags ^ prev.flags) & 0x3) == 0) {
  21810. prev.flags |= next.flags;
  21811. continue;
  21812. } else if (prev.flags & UFBX_BAKED_KEY_STEP_LEFT) {
  21813. next.flags |= UFBX_BAKED_KEY_STEP_KEY;
  21814. } else if (next.flags & UFBX_BAKED_KEY_STEP_RIGHT) {
  21815. prev.flags |= UFBX_BAKED_KEY_STEP_KEY;
  21816. }
  21817. }
  21818. times[dst++] = prev;
  21819. prev = next;
  21820. }
  21821. times[dst++] = prev;
  21822. num_times = dst;
  21823. }
  21824. // Cull too close resampled keys, these may arise during merging multiple times
  21825. if (num_times > 0) {
  21826. double min_dist = 0.25 / bc->opts.resample_rate;
  21827. uint32_t keep_flags = UFBX_BAKED_KEY_STEP_LEFT|UFBX_BAKED_KEY_STEP_RIGHT|UFBX_BAKED_KEY_STEP_KEY|UFBX_BAKED_KEY_KEYFRAME;
  21828. size_t dst = 0;
  21829. for (size_t src = 0; src < num_times; src++) {
  21830. ufbxi_bake_time cur = times[src];
  21831. double delta = UFBX_INFINITY;
  21832. bool keep = true;
  21833. if ((cur.flags & keep_flags) == 0) {
  21834. if (dst > 0) delta = cur.time - times[dst - 1].time;
  21835. if (src + 1 < num_times) delta = ufbx_fmin(delta, times[src + 1].time - cur.time);
  21836. if (delta < min_dist) keep = false;
  21837. }
  21838. if (keep) {
  21839. times[dst++] = cur;
  21840. }
  21841. }
  21842. num_times = dst;
  21843. }
  21844. // Enforce maximum sample rate
  21845. if (bc->opts.maximum_sample_rate > 0.0) {
  21846. const double epsilon = 0.0078125 / bc->opts.maximum_sample_rate;
  21847. double sample_rate = bc->opts.maximum_sample_rate;
  21848. double max_interval = 1.0 / bc->opts.maximum_sample_rate;
  21849. double min_interval = 1.0 / bc->opts.maximum_sample_rate - epsilon;
  21850. size_t dst = 0, src = 0;
  21851. // Pre-expand constant keyframes
  21852. for (size_t i = 0; i < num_times; i++) {
  21853. if ((times[i].flags & (UFBX_BAKED_KEY_STEP_LEFT|UFBX_BAKED_KEY_STEP_RIGHT)) != 0) {
  21854. double sign = (times[i].flags & UFBX_BAKED_KEY_STEP_LEFT) != 0 ? -1.0 : 1.0;
  21855. double time = times[i].time + sign * max_interval;
  21856. if (i > 0) time = ufbx_fmax(time, times[i - 1].time);
  21857. if (i + 1 < num_times) time = ufbx_fmin(time, times[i + 1].time);
  21858. times[i].time = time;
  21859. times[i].flags = UFBX_BAKED_KEY_REDUCED;
  21860. }
  21861. }
  21862. ufbxi_bake_time prev_time = { -UFBX_INFINITY };
  21863. while (src < num_times) {
  21864. ufbxi_bake_time src_time = times[src];
  21865. src++;
  21866. size_t start_src = src;
  21867. ufbxi_bake_time next_time;
  21868. next_time.time = ufbx_ceil(src_time.time * sample_rate - epsilon) / sample_rate;
  21869. next_time.flags = UFBX_BAKED_KEY_REDUCED;
  21870. while (src < num_times && times[src].time <= next_time.time + epsilon) {
  21871. src++;
  21872. }
  21873. if (src != start_src || src_time.time - prev_time.time <= min_interval) {
  21874. prev_time = next_time;
  21875. } else {
  21876. prev_time = src_time;
  21877. }
  21878. if (dst == 0 || prev_time.time > times[dst - 1].time) {
  21879. times[dst++] = prev_time;
  21880. }
  21881. }
  21882. num_times = dst;
  21883. }
  21884. if (num_times > 0) {
  21885. if (times[0].time < bc->time_min) bc->time_min = times[0].time;
  21886. if (times[num_times - 1].time > bc->time_max) bc->time_max = times[num_times - 1].time;
  21887. }
  21888. p_dst->data = times;
  21889. p_dst->count = num_times;
  21890. return 1;
  21891. }
  21892. #define ufbxi_add_epsilon(a, epsilon) ((a)>0 ? (a)*(epsilon) : (a)/(epsilon))
  21893. #define ufbxi_sub_epsilon(a, epsilon) ((a)>0 ? (a)/(epsilon) : (a)*(epsilon))
  21894. static ufbxi_noinline bool ufbxi_postprocess_step(ufbxi_bake_context *bc, double prev_time, double next_time, double *p_time, uint32_t flags)
  21895. {
  21896. ufbxi_dev_assert((flags & (UFBX_BAKED_KEY_STEP_LEFT|UFBX_BAKED_KEY_STEP_RIGHT)) != 0);
  21897. bool left = (flags & UFBX_BAKED_KEY_STEP_LEFT) != 0;
  21898. double step = 0.001;
  21899. double epsilon = 1.0 + FLT_EPSILON * 4.0f;
  21900. double time = *p_time;
  21901. switch (bc->opts.step_handling) {
  21902. case UFBX_BAKE_STEP_HANDLING_DEFAULT:
  21903. break;
  21904. case UFBX_BAKE_STEP_HANDLING_CUSTOM_DURATION:
  21905. step = bc->opts.step_custom_duration;
  21906. epsilon = 1.0 + bc->opts.step_custom_epsilon;
  21907. break;
  21908. case UFBX_BAKE_STEP_HANDLING_IDENTICAL_TIME:
  21909. return true;
  21910. case UFBX_BAKE_STEP_HANDLING_ADJACENT_DOUBLE:
  21911. if (left) {
  21912. *p_time = time = ufbx_nextafter(time, -UFBX_INFINITY);
  21913. return time > prev_time;
  21914. } else {
  21915. *p_time = time = ufbx_nextafter(time, UFBX_INFINITY);
  21916. return time < next_time;
  21917. }
  21918. case UFBX_BAKE_STEP_HANDLING_IGNORE:
  21919. return false;
  21920. default:
  21921. ufbxi_unreachable("Unhandled bake step handling");
  21922. return false;
  21923. }
  21924. if (left) {
  21925. double min_time = ufbx_fmax(prev_time + step, ufbxi_add_epsilon(prev_time, epsilon));
  21926. *p_time = time = ufbx_fmin(time - step, ufbxi_sub_epsilon(time, epsilon));
  21927. return time > min_time;
  21928. } else {
  21929. double max_time = ufbx_fmin(next_time - step, ufbxi_sub_epsilon(next_time, epsilon));
  21930. *p_time = time = ufbx_fmax(time + step, ufbxi_add_epsilon(time, epsilon));
  21931. return time < max_time;
  21932. }
  21933. }
  21934. ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_postprocess_vec3(ufbxi_bake_context *bc, ufbx_baked_vec3_list *p_dst, bool *p_constant, ufbx_baked_vec3_list src)
  21935. {
  21936. if (src.count == 0) return 1;
  21937. // Offset times
  21938. if (bc->ktime_offset != 0.0) {
  21939. double scale = (double)bc->scene->metadata.ktime_second;
  21940. double offset = bc->ktime_offset;
  21941. for (size_t i = 0; i < src.count; i++) {
  21942. src.data[i].time = ufbx_rint(src.data[i].time * scale + offset) / scale;
  21943. }
  21944. }
  21945. // Postprocess stepped tangents
  21946. {
  21947. size_t dst = 0;
  21948. double prev_time = src.data[0].time;
  21949. for (size_t i = 0; i < src.count; i++) {
  21950. ufbx_baked_vec3 cur = src.data[i];
  21951. double next_time = i + 1 < src.count ? src.data[i + 1].time : UFBX_INFINITY;
  21952. bool keep = true;
  21953. if ((cur.flags & (UFBX_BAKED_KEY_STEP_LEFT|UFBX_BAKED_KEY_STEP_RIGHT)) != 0) {
  21954. keep = ufbxi_postprocess_step(bc, prev_time, next_time, &cur.time, cur.flags);
  21955. }
  21956. if (keep) {
  21957. src.data[dst] = cur;
  21958. dst++;
  21959. prev_time = cur.time;
  21960. }
  21961. }
  21962. src.count = dst;
  21963. }
  21964. if (bc->opts.key_reduction_enabled) {
  21965. double threshold = bc->opts.key_reduction_threshold * bc->opts.key_reduction_threshold;
  21966. for (size_t pass = 0; pass < bc->opts.key_reduction_passes; pass++) {
  21967. size_t dst = 1;
  21968. for (size_t i = 1; i < src.count; i++) {
  21969. ufbx_baked_vec3 prev = src.data[i - 1];
  21970. ufbx_baked_vec3 cur = src.data[i];
  21971. if (i + 1 < src.count) {
  21972. ufbx_baked_vec3 next = src.data[i + 1];
  21973. double delta = (cur.time - prev.time) / (next.time - prev.time);
  21974. ufbx_vec3 tmp = ufbxi_lerp3(prev.value, next.value, (ufbx_real)delta);
  21975. double error = 0.0;
  21976. error += ((double)tmp.x - (double)cur.value.x) * ((double)tmp.x - (double)cur.value.x);
  21977. error += ((double)tmp.y - (double)cur.value.y) * ((double)tmp.y - (double)cur.value.y);
  21978. error += ((double)tmp.z - (double)cur.value.z) * ((double)tmp.z - (double)cur.value.z);
  21979. if (error <= threshold) {
  21980. src.data[dst] = src.data[i + 1];
  21981. i += 1;
  21982. dst += 1;
  21983. continue;
  21984. }
  21985. }
  21986. src.data[dst] = src.data[i];
  21987. dst += 1;
  21988. }
  21989. if (dst == src.count) break;
  21990. src.count = dst;
  21991. }
  21992. }
  21993. bool constant = true;
  21994. ufbx_vec3 ref = src.data[0].value;
  21995. for (size_t i = 1; i < src.count; i++) {
  21996. ufbx_vec3 v = src.data[i].value;
  21997. if (v.x != ref.x || v.y != ref.y || v.z != ref.z) {
  21998. constant = false;
  21999. break;
  22000. }
  22001. }
  22002. *p_constant = constant;
  22003. p_dst->count = src.count;
  22004. p_dst->data = ufbxi_push_copy(&bc->result, ufbx_baked_vec3, src.count, src.data);
  22005. ufbxi_check_err(&bc->error, p_dst->data);
  22006. return 1;
  22007. }
  22008. ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_postprocess_quat(ufbxi_bake_context *bc, ufbx_baked_quat_list *p_dst, bool *p_constant, ufbx_baked_quat_list src)
  22009. {
  22010. if (src.count == 0) return 1;
  22011. // Offset times
  22012. if (bc->ktime_offset != 0.0) {
  22013. double scale = (double)bc->scene->metadata.ktime_second;
  22014. double offset = bc->ktime_offset;
  22015. for (size_t i = 0; i < src.count; i++) {
  22016. src.data[i].time = ufbx_rint(src.data[i].time * scale + offset) / scale;
  22017. }
  22018. }
  22019. // Postprocess stepped tangents
  22020. {
  22021. size_t dst = 0;
  22022. double prev_time = src.data[0].time;
  22023. for (size_t i = 0; i < src.count; i++) {
  22024. ufbx_baked_quat cur = src.data[i];
  22025. double next_time = i + 1 < src.count ? src.data[i + 1].time : UFBX_INFINITY;
  22026. bool keep = true;
  22027. if ((cur.flags & (UFBX_BAKED_KEY_STEP_LEFT|UFBX_BAKED_KEY_STEP_RIGHT)) != 0) {
  22028. keep = ufbxi_postprocess_step(bc, prev_time, next_time, &cur.time, cur.flags);
  22029. }
  22030. if (keep) {
  22031. prev_time = cur.time;
  22032. src.data[dst] = cur;
  22033. dst++;
  22034. }
  22035. }
  22036. src.count = dst;
  22037. }
  22038. // Fix quaternion antipodality
  22039. for (size_t i = 1; i < src.count; i++) {
  22040. src.data[i].value = ufbx_quat_fix_antipodal(src.data[i].value, src.data[i - 1].value);
  22041. }
  22042. if (bc->opts.key_reduction_enabled) {
  22043. double threshold = bc->opts.key_reduction_threshold * bc->opts.key_reduction_threshold;
  22044. for (size_t pass = 0; pass < bc->opts.key_reduction_passes; pass++) {
  22045. size_t dst = 1;
  22046. for (size_t i = 1; i < src.count; i++) {
  22047. ufbx_baked_quat prev = src.data[i - 1];
  22048. ufbx_baked_quat cur = src.data[i];
  22049. if (i + 1 < src.count) {
  22050. ufbx_baked_quat next = src.data[i + 1];
  22051. double delta = (cur.time - prev.time) / (next.time - prev.time);
  22052. double error = 0.0;
  22053. if (bc->opts.key_reduction_rotation) {
  22054. ufbx_quat tmp = ufbx_quat_slerp(prev.value, next.value, (ufbx_real)delta);
  22055. error += ((double)tmp.x - (double)cur.value.x) * ((double)tmp.x - (double)cur.value.x);
  22056. error += ((double)tmp.y - (double)cur.value.y) * ((double)tmp.y - (double)cur.value.y);
  22057. error += ((double)tmp.z - (double)cur.value.z) * ((double)tmp.z - (double)cur.value.z);
  22058. error += ((double)tmp.w - (double)cur.value.w) * ((double)tmp.w - (double)cur.value.w);
  22059. } else {
  22060. error += ((double)prev.value.x - (double)cur.value.x) * ((double)prev.value.x - (double)cur.value.x);
  22061. error += ((double)prev.value.y - (double)cur.value.y) * ((double)prev.value.y - (double)cur.value.y);
  22062. error += ((double)prev.value.z - (double)cur.value.z) * ((double)prev.value.z - (double)cur.value.z);
  22063. error += ((double)prev.value.w - (double)cur.value.w) * ((double)prev.value.w - (double)cur.value.w);
  22064. error += ((double)next.value.x - (double)cur.value.x) * ((double)next.value.x - (double)cur.value.x);
  22065. error += ((double)next.value.y - (double)cur.value.y) * ((double)next.value.y - (double)cur.value.y);
  22066. error += ((double)next.value.z - (double)cur.value.z) * ((double)next.value.z - (double)cur.value.z);
  22067. error += ((double)next.value.w - (double)cur.value.w) * ((double)next.value.w - (double)cur.value.w);
  22068. error *= 0.5;
  22069. }
  22070. if (error <= threshold) {
  22071. src.data[dst] = src.data[i + 1];
  22072. i += 1;
  22073. dst += 1;
  22074. continue;
  22075. }
  22076. }
  22077. src.data[dst] = src.data[i];
  22078. dst += 1;
  22079. }
  22080. if (dst == src.count) break;
  22081. src.count = dst;
  22082. }
  22083. }
  22084. bool constant = true;
  22085. ufbx_quat ref = src.data[0].value;
  22086. for (size_t i = 1; i < src.count; i++) {
  22087. ufbx_quat v = src.data[i].value;
  22088. if (v.x != ref.x || v.y != ref.y || v.z != ref.z || v.y != ref.w) {
  22089. constant = false;
  22090. break;
  22091. }
  22092. }
  22093. *p_constant = constant;
  22094. p_dst->count = src.count;
  22095. p_dst->data = ufbxi_push_copy(&bc->result, ufbx_baked_quat, src.count, src.data);
  22096. ufbxi_check_err(&bc->error, p_dst->data);
  22097. return 1;
  22098. }
  22099. static ufbxi_forceinline double ufbxi_bake_time_sample_time(ufbxi_bake_time time)
  22100. {
  22101. // Move an infinitesimal step for stepped tangents
  22102. if ((time.flags & (UFBX_BAKED_KEY_STEP_LEFT|UFBX_BAKED_KEY_STEP_RIGHT)) != 0) {
  22103. double dir = (time.flags & UFBX_BAKED_KEY_STEP_LEFT) != 0 ? -UFBX_INFINITY : UFBX_INFINITY;
  22104. return ufbx_nextafter(time.time, dir);
  22105. } else {
  22106. return time.time;
  22107. }
  22108. }
  22109. ufbxi_nodiscard static ufbxi_noinline int ufbxi_push_resampled_times(ufbxi_bake_context *bc, const ufbx_baked_vec3_list *p_keys)
  22110. {
  22111. ufbx_baked_vec3_list keys = *p_keys;
  22112. ufbxi_bake_time *times = ufbxi_push(&bc->tmp_times, ufbxi_bake_time, keys.count);
  22113. ufbxi_check_err(&bc->error, times);
  22114. for (size_t i = 0; i < keys.count; i++) {
  22115. uint32_t flags = keys.data[i].flags;
  22116. double time = keys.data[i].time;
  22117. if ((flags & UFBX_BAKED_KEY_STEP_LEFT) != 0 && i + 1 < keys.count && (keys.data[i + 1].flags & UFBX_BAKED_KEY_STEP_KEY) != 0) {
  22118. time = keys.data[i + 1].time;
  22119. } else if ((flags & UFBX_BAKED_KEY_STEP_RIGHT) != 0 && i > 0 && (keys.data[i - 1].flags & UFBX_BAKED_KEY_STEP_KEY) != 0) {
  22120. time = keys.data[i - 1].time;
  22121. }
  22122. times[i].time = time;
  22123. times[i].flags = flags & 0x7;
  22124. }
  22125. return 1;
  22126. }
  22127. ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_node_imp(ufbxi_bake_context *bc, uint32_t element_id, ufbxi_bake_prop *props, size_t count)
  22128. {
  22129. ufbx_assert(bc->baked_nodes && bc->nodes_to_bake);
  22130. ufbx_node *node = (ufbx_node*)bc->scene->elements.data[element_id];
  22131. ufbxi_dev_assert(node->element.type == UFBX_ELEMENT_NODE);
  22132. bool complex_translation = false;
  22133. bool complex_rotation = false;
  22134. for (size_t i = 0; i < ufbxi_arraycount(ufbxi_complex_translation_props); i++) {
  22135. const char *name = ufbxi_complex_translation_props[i];
  22136. ufbx_prop *prop = ufbxi_find_prop(&node->props, name);
  22137. if (prop && !ufbxi_is_vec3_zero(prop->value_vec3)) {
  22138. complex_translation = true;
  22139. }
  22140. ufbxi_for(ufbxi_bake_prop, bprop, props, count) {
  22141. if (bprop->prop_name == name) {
  22142. complex_translation = true;
  22143. }
  22144. }
  22145. }
  22146. for (size_t i = 0; i < ufbxi_arraycount(ufbxi_complex_rotation_props); i++) {
  22147. const char *name = ufbxi_complex_rotation_props[i];
  22148. ufbxi_for(ufbxi_bake_prop, bprop, props, count) {
  22149. if (bprop->prop_name == name) {
  22150. complex_rotation = true;
  22151. }
  22152. }
  22153. }
  22154. ufbxi_bake_time_list times_t, times_r, times_s;
  22155. // Translation
  22156. bool resample_translation = false;
  22157. // Account for the _resampled_ scale helper scale animation to keep the
  22158. // translation scale consistent with the parent scaling.
  22159. ufbx_baked_node *scale_helper_t = NULL;
  22160. ufbx_vec3 constant_scale_t = { 1.0f, 1.0f, 1.0f };
  22161. if (!node->is_scale_helper && node->parent && node->parent->scale_helper) {
  22162. scale_helper_t = bc->baked_nodes[node->parent->scale_helper->typed_id];
  22163. if (scale_helper_t) {
  22164. if (!scale_helper_t->constant_scale) {
  22165. resample_translation = true;
  22166. }
  22167. ufbxi_check_err(&bc->error, ufbxi_push_resampled_times(bc, &scale_helper_t->scale_keys));
  22168. } else {
  22169. constant_scale_t = node->parent->scale_helper->inherit_scale;
  22170. }
  22171. }
  22172. if (complex_translation) {
  22173. ufbxi_for(ufbxi_bake_prop, prop, props, count) {
  22174. // Literally any transform related property can affect complex translation
  22175. if (ufbxi_in_list(ufbxi_transform_props, ufbxi_arraycount(ufbxi_transform_props), prop->prop_name)) {
  22176. bool resample_linear = resample_translation || prop->prop_name != ufbxi_Lcl_Translation;
  22177. uint32_t key_flag = prop->prop_name == ufbxi_Lcl_Translation ? UFBX_BAKED_KEY_KEYFRAME : 0;
  22178. ufbxi_check_err(&bc->error, ufbxi_bake_times(bc, prop->anim_value, resample_linear, key_flag));
  22179. }
  22180. }
  22181. } else {
  22182. ufbxi_for(ufbxi_bake_prop, prop, props, count) {
  22183. if (prop->prop_name == ufbxi_Lcl_Translation) {
  22184. ufbxi_check_err(&bc->error, ufbxi_bake_times(bc, prop->anim_value, resample_translation, UFBX_BAKED_KEY_KEYFRAME));
  22185. }
  22186. }
  22187. }
  22188. ufbxi_check_err(&bc->error, ufbxi_finalize_bake_times(bc, &times_t));
  22189. // Rotation
  22190. if (complex_rotation) {
  22191. ufbxi_for(ufbxi_bake_prop, prop, props, count) {
  22192. if (ufbxi_in_list(ufbxi_complex_rotation_sources, ufbxi_arraycount(ufbxi_complex_rotation_sources), prop->prop_name)) {
  22193. bool resample_linear = !bc->opts.no_resample_rotation || prop->prop_name != ufbxi_Lcl_Rotation;
  22194. uint32_t key_flag = prop->prop_name == ufbxi_Lcl_Rotation ? UFBX_BAKED_KEY_KEYFRAME : 0;
  22195. ufbxi_check_err(&bc->error, ufbxi_bake_times(bc, prop->anim_value, resample_linear, key_flag));
  22196. }
  22197. }
  22198. } else {
  22199. ufbxi_for(ufbxi_bake_prop, prop, props, count) {
  22200. if (prop->prop_name == ufbxi_Lcl_Rotation) {
  22201. ufbxi_check_err(&bc->error, ufbxi_bake_times(bc, prop->anim_value, !bc->opts.no_resample_rotation, UFBX_BAKED_KEY_KEYFRAME));
  22202. }
  22203. }
  22204. }
  22205. ufbxi_check_err(&bc->error, ufbxi_finalize_bake_times(bc, &times_r));
  22206. // Scaling
  22207. bool resample_scale = false;
  22208. // Account for the resampled scale
  22209. ufbx_baked_node *scale_helper_s = NULL;
  22210. ufbx_vec3 constant_scale_s = { 1.0f, 1.0f, 1.0f };
  22211. if (node->is_scale_helper && node->parent && node->parent->inherit_scale_node && node->parent->inherit_scale_node->scale_helper) {
  22212. ufbx_node *inherit_helper = node->parent->inherit_scale_node->scale_helper;
  22213. scale_helper_s = bc->baked_nodes[inherit_helper->typed_id];
  22214. if (scale_helper_s) {
  22215. if (!scale_helper_s->constant_scale) {
  22216. resample_scale = true;
  22217. }
  22218. ufbxi_check_err(&bc->error, ufbxi_push_resampled_times(bc, &scale_helper_s->scale_keys));
  22219. } else {
  22220. constant_scale_s = inherit_helper->local_transform.scale;
  22221. }
  22222. }
  22223. ufbxi_for(ufbxi_bake_prop, prop, props, count) {
  22224. if (prop->prop_name == ufbxi_Lcl_Scaling) {
  22225. ufbxi_check_err(&bc->error, ufbxi_bake_times(bc, prop->anim_value, resample_scale, UFBX_BAKED_KEY_KEYFRAME));
  22226. }
  22227. }
  22228. ufbxi_check_err(&bc->error, ufbxi_finalize_bake_times(bc, &times_s));
  22229. ufbx_baked_vec3_list keys_t;
  22230. ufbx_baked_quat_list keys_r;
  22231. ufbx_baked_vec3_list keys_s;
  22232. keys_t.count = times_t.count;
  22233. keys_t.data = ufbxi_push(&bc->tmp_prop, ufbx_baked_vec3, keys_t.count);
  22234. ufbxi_check_err(&bc->error, keys_t.data);
  22235. keys_r.count = times_r.count;
  22236. keys_r.data = ufbxi_push(&bc->tmp_prop, ufbx_baked_quat, keys_r.count);
  22237. ufbxi_check_err(&bc->error, keys_r.data);
  22238. keys_s.count = times_s.count;
  22239. keys_s.data = ufbxi_push(&bc->tmp_prop, ufbx_baked_vec3, keys_s.count);
  22240. ufbxi_check_err(&bc->error, keys_s.data);
  22241. size_t ix_t = 0, ix_r = 0, ix_s = 0;
  22242. while (ix_t < times_t.count || ix_r < times_r.count || ix_s < times_s.count) {
  22243. ufbxi_bake_time bake_time = { UFBX_INFINITY };
  22244. uint32_t flags_r = 0, flags_t = 0, flags_s = 0;
  22245. uint32_t flags = 0;
  22246. if (ix_r < times_r.count) {
  22247. bake_time = times_r.data[ix_r];
  22248. flags_r = bake_time.flags;
  22249. bake_time.flags &= 0x7;
  22250. flags |= UFBX_TRANSFORM_FLAG_INCLUDE_ROTATION;
  22251. }
  22252. if (ix_t < times_t.count) {
  22253. ufbxi_bake_time t = times_t.data[ix_t];
  22254. int cmp = ufbxi_cmp_bake_time(t, bake_time);
  22255. if (cmp <= 0) {
  22256. if (cmp < 0) {
  22257. bake_time = t;
  22258. flags = 0;
  22259. }
  22260. bake_time.flags |= t.flags & 0x7;
  22261. flags_t = t.flags;
  22262. flags |= UFBX_TRANSFORM_FLAG_INCLUDE_TRANSLATION;
  22263. }
  22264. }
  22265. if (ix_s < times_s.count) {
  22266. ufbxi_bake_time t = times_s.data[ix_s];
  22267. int cmp = ufbxi_cmp_bake_time(t, bake_time);
  22268. if (cmp <= 0) {
  22269. if (cmp < 0) {
  22270. bake_time = t;
  22271. flags = 0;
  22272. }
  22273. bake_time.flags |= t.flags & 0x7;
  22274. flags_s = t.flags;
  22275. flags |= UFBX_TRANSFORM_FLAG_INCLUDE_SCALE;
  22276. }
  22277. }
  22278. flags |= UFBX_TRANSFORM_FLAG_IGNORE_SCALE_HELPER|UFBX_TRANSFORM_FLAG_IGNORE_COMPONENTWISE_SCALE|UFBX_TRANSFORM_FLAG_EXPLICIT_INCLUDES;
  22279. double eval_time = ufbxi_bake_time_sample_time(bake_time);
  22280. ufbx_transform transform = ufbx_evaluate_transform_flags(bc->anim, node, eval_time, flags);
  22281. if (flags & UFBX_TRANSFORM_FLAG_INCLUDE_TRANSLATION) {
  22282. if (scale_helper_t) {
  22283. ufbx_vec3 scale = ufbx_evaluate_baked_vec3(scale_helper_t->scale_keys, eval_time);
  22284. transform.translation.x *= scale.x;
  22285. transform.translation.y *= scale.y;
  22286. transform.translation.z *= scale.z;
  22287. }
  22288. transform.translation.x *= constant_scale_t.x;
  22289. transform.translation.y *= constant_scale_t.y;
  22290. transform.translation.z *= constant_scale_t.z;
  22291. keys_t.data[ix_t].time = bake_time.time;
  22292. keys_t.data[ix_t].value = transform.translation;
  22293. keys_t.data[ix_t].flags = (ufbx_baked_key_flags)(bake_time.flags | flags_t);
  22294. ix_t++;
  22295. }
  22296. if (flags & UFBX_TRANSFORM_FLAG_INCLUDE_ROTATION) {
  22297. keys_r.data[ix_r].time = bake_time.time;
  22298. keys_r.data[ix_r].value = transform.rotation;
  22299. keys_r.data[ix_r].flags = (ufbx_baked_key_flags)(bake_time.flags | flags_r);
  22300. ix_r++;
  22301. }
  22302. if (flags & UFBX_TRANSFORM_FLAG_INCLUDE_SCALE) {
  22303. if (scale_helper_s) {
  22304. ufbx_vec3 scale = ufbx_evaluate_baked_vec3(scale_helper_s->scale_keys, eval_time);
  22305. transform.scale.x *= scale.x;
  22306. transform.scale.y *= scale.y;
  22307. transform.scale.z *= scale.z;
  22308. }
  22309. transform.scale.x *= constant_scale_s.x;
  22310. transform.scale.y *= constant_scale_s.y;
  22311. transform.scale.z *= constant_scale_s.z;
  22312. keys_s.data[ix_s].time = bake_time.time;
  22313. keys_s.data[ix_s].value = transform.scale;
  22314. keys_s.data[ix_s].flags = (ufbx_baked_key_flags)(bake_time.flags | flags_s);
  22315. ix_s++;
  22316. }
  22317. }
  22318. ufbx_baked_node *baked_node = ufbxi_push_zero(&bc->tmp_nodes, ufbx_baked_node, 1);
  22319. ufbxi_check_err(&bc->error, baked_node);
  22320. baked_node->element_id = node->element_id;
  22321. baked_node->typed_id = node->typed_id;
  22322. ufbxi_check_err(&bc->error, ufbxi_bake_postprocess_vec3(bc, &baked_node->translation_keys, &baked_node->constant_translation, keys_t));
  22323. ufbxi_check_err(&bc->error, ufbxi_bake_postprocess_quat(bc, &baked_node->rotation_keys, &baked_node->constant_rotation, keys_r));
  22324. ufbxi_check_err(&bc->error, ufbxi_bake_postprocess_vec3(bc, &baked_node->scale_keys, &baked_node->constant_scale, keys_s));
  22325. bc->baked_nodes[node->typed_id] = baked_node;
  22326. ufbxi_buf_clear(&bc->tmp_prop);
  22327. // If this node is a scale helper, make sure to bake its siblings and
  22328. // potentially their scale helpers if they are not a part of the animation.
  22329. if (node->is_scale_helper) {
  22330. ufbx_assert(node->parent);
  22331. ufbxi_for_ptr_list(ufbx_node, p_child, node->parent->children) {
  22332. ufbx_node *child = *p_child;
  22333. if (child == node) continue;
  22334. if (!bc->nodes_to_bake[child->typed_id]) {
  22335. bc->nodes_to_bake[child->typed_id] = true;
  22336. ufbxi_check_err(&bc->error, ufbxi_push_copy(&bc->tmp_bake_stack, uint32_t, 1, &child->element_id));
  22337. }
  22338. if (child->inherit_scale_node && child->inherit_scale_node->scale_helper && child->scale_helper
  22339. && bc->nodes_to_bake[child->inherit_scale_node->scale_helper->typed_id]) {
  22340. ufbx_assert(bc->baked_nodes[child->inherit_scale_node->scale_helper->typed_id]);
  22341. if (!bc->nodes_to_bake[child->scale_helper->typed_id]) {
  22342. bc->nodes_to_bake[child->scale_helper->typed_id] = true;
  22343. ufbxi_check_err(&bc->error, ufbxi_push_copy(&bc->tmp_bake_stack, uint32_t, 1, &child->scale_helper->element_id));
  22344. }
  22345. }
  22346. }
  22347. }
  22348. return 1;
  22349. }
  22350. ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_node(ufbxi_bake_context *bc, uint32_t element_id, ufbxi_bake_prop *props, size_t count)
  22351. {
  22352. ufbxi_check_err(&bc->error, ufbxi_bake_node_imp(bc, element_id, props, count));
  22353. // Baking a node may cause further nodes to be baked, so keep going
  22354. // until all dependencies are baked.
  22355. while (bc->tmp_bake_stack.num_items > 0) {
  22356. uint32_t child_id = 0;
  22357. ufbxi_pop(&bc->tmp_bake_stack, uint32_t, 1, &child_id);
  22358. ufbxi_check_err(&bc->error, ufbxi_bake_node_imp(bc, child_id, NULL, 0));
  22359. }
  22360. return 1;
  22361. }
  22362. ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_anim_prop(ufbxi_bake_context *bc, ufbx_element *element, const char *prop_name, ufbxi_bake_prop *props, size_t count)
  22363. {
  22364. ufbxi_for(ufbxi_bake_prop, prop, props, count) {
  22365. ufbxi_check_err(&bc->error, ufbxi_bake_times(bc, prop->anim_value, false, UFBX_BAKED_KEY_KEYFRAME));
  22366. }
  22367. ufbxi_bake_time_list times;
  22368. ufbxi_check_err(&bc->error, ufbxi_finalize_bake_times(bc, &times));
  22369. ufbx_baked_vec3_list keys;
  22370. keys.count = times.count;
  22371. keys.data = ufbxi_push(&bc->tmp_prop, ufbx_baked_vec3, keys.count);
  22372. ufbxi_check_err(&bc->error, keys.data);
  22373. ufbx_string name;
  22374. name.data = prop_name;
  22375. name.length = strlen(prop_name);
  22376. for (size_t i = 0; i < times.count; i++) {
  22377. ufbxi_bake_time bake_time = times.data[i];
  22378. double eval_time = ufbxi_bake_time_sample_time(bake_time);
  22379. ufbx_prop prop = ufbx_evaluate_prop_len(bc->anim, element, name.data, name.length, eval_time);
  22380. keys.data[i].time = bake_time.time;
  22381. keys.data[i].value = prop.value_vec3;
  22382. keys.data[i].flags = (ufbx_baked_key_flags)bake_time.flags;
  22383. }
  22384. ufbx_baked_prop *baked_prop = ufbxi_push_zero(&bc->tmp_props, ufbx_baked_prop, 1);
  22385. ufbxi_check_err(&bc->error, baked_prop);
  22386. baked_prop->name.length = strlen(prop_name);
  22387. baked_prop->name.data = ufbxi_push_copy(&bc->result, char, baked_prop->name.length + 1, prop_name);
  22388. ufbxi_check_err(&bc->error, baked_prop->name.data);
  22389. ufbxi_check_err(&bc->error, ufbxi_bake_postprocess_vec3(bc, &baked_prop->keys, &baked_prop->constant_value, keys));
  22390. ufbxi_buf_clear(&bc->tmp_prop);
  22391. return 1;
  22392. }
  22393. ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_element(ufbxi_bake_context *bc, uint32_t element_id, ufbxi_bake_prop *props, size_t count)
  22394. {
  22395. ufbx_element *element = bc->scene->elements.data[element_id];
  22396. if (element->type == UFBX_ELEMENT_NODE && !bc->opts.skip_node_transforms) {
  22397. ufbxi_check_err(&bc->error, ufbxi_bake_node(bc, element_id, props, count));
  22398. }
  22399. size_t begin = 0;
  22400. while (begin < count) {
  22401. const char *prop_name = props[begin].prop_name;
  22402. size_t end = begin + 1;
  22403. while (end < count && props[end].prop_name == prop_name) {
  22404. end++;
  22405. }
  22406. // Don't bake transform related props for nodes unless specifically requested
  22407. if (element->type == UFBX_ELEMENT_NODE && !bc->opts.bake_transform_props && ufbxi_in_list(ufbxi_transform_props, ufbxi_arraycount(ufbxi_transform_props), prop_name)) {
  22408. begin = end;
  22409. continue;
  22410. }
  22411. ufbxi_check_err(&bc->error, ufbxi_bake_anim_prop(bc, element, prop_name, props + begin, end - begin));
  22412. begin = end;
  22413. }
  22414. size_t num_props = bc->tmp_props.num_items;
  22415. if (num_props > 0) {
  22416. ufbx_baked_element *baked_elem = ufbxi_push_zero(&bc->tmp_elements, ufbx_baked_element, 1);
  22417. ufbxi_check_err(&bc->error, baked_elem);
  22418. baked_elem->element_id = element->element_id;
  22419. baked_elem->props.count = num_props;
  22420. baked_elem->props.data = ufbxi_push_pop(&bc->result, &bc->tmp_props, ufbx_baked_prop, num_props);
  22421. ufbxi_check_err(&bc->error, baked_elem->props.data);
  22422. }
  22423. return 1;
  22424. }
  22425. static ufbxi_noinline bool ufbxi_baked_node_less(void *user, const void *va, const void *vb)
  22426. {
  22427. (void)user;
  22428. const ufbx_baked_node *a = (const ufbx_baked_node*)va, *b = (const ufbx_baked_node*)vb;
  22429. return a->typed_id < b->typed_id;
  22430. }
  22431. static ufbxi_noinline bool ufbxi_baked_element_less(void *user, const void *va, const void *vb)
  22432. {
  22433. (void)user;
  22434. const ufbx_baked_element *a = (const ufbx_baked_element*)va, *b = (const ufbx_baked_element*)vb;
  22435. return a->element_id < b->element_id;
  22436. }
  22437. ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_anim(ufbxi_bake_context *bc)
  22438. {
  22439. const ufbx_anim *anim = bc->anim;
  22440. const ufbx_scene *scene = bc->scene;
  22441. if (!bc->opts.skip_node_transforms) {
  22442. bc->baked_nodes = ufbxi_push_zero(&bc->result, ufbx_baked_node*, scene->nodes.count);
  22443. ufbxi_check_err(&bc->error, bc->baked_nodes);
  22444. bc->nodes_to_bake = ufbxi_push_zero(&bc->result, bool, scene->nodes.count);
  22445. ufbxi_check_err(&bc->error, bc->nodes_to_bake);
  22446. }
  22447. ufbxi_for_ptr_list(ufbx_anim_layer, p_layer, anim->layers) {
  22448. ufbx_anim_layer *layer = *p_layer;
  22449. ufbxi_for_list(ufbx_anim_prop, anim_prop, layer->anim_props) {
  22450. ufbxi_bake_prop *prop = ufbxi_push(&bc->tmp_bake_props, ufbxi_bake_prop, 1);
  22451. ufbxi_check_err(&bc->error, prop);
  22452. ufbx_element *element = anim_prop->element;
  22453. // Sort nodes by `typed_id` to make sure we process them in order.
  22454. if (element->type == UFBX_ELEMENT_NODE) {
  22455. if (bc->nodes_to_bake) {
  22456. bc->nodes_to_bake[element->typed_id] = true;
  22457. }
  22458. prop->sort_id = element->typed_id;
  22459. } else {
  22460. prop->sort_id = UINT32_MAX;
  22461. }
  22462. prop->element_id = element->element_id;
  22463. prop->prop_name = anim_prop->prop_name.data;
  22464. prop->anim_value = anim_prop->anim_value;
  22465. }
  22466. }
  22467. size_t num_props = bc->tmp_bake_props.num_items;
  22468. ufbxi_bake_prop *props = ufbxi_push_pop(&bc->tmp, &bc->tmp_bake_props, ufbxi_bake_prop, num_props);
  22469. ufbxi_check_err(&bc->error, props);
  22470. // TODO: Macro unstable/non allocating sort
  22471. qsort(props, num_props, sizeof(ufbxi_bake_prop), &ufbxi_cmp_bake_prop);
  22472. // Pre-bake layer weight times
  22473. if (!bc->opts.ignore_layer_weight_animation) {
  22474. bool has_weight_times = false;
  22475. ufbxi_for(ufbxi_bake_prop, prop, props, num_props) {
  22476. if (prop->prop_name != ufbxi_Weight) continue;
  22477. ufbx_element *element = scene->elements.data[prop->element_id];
  22478. if (element->type == UFBX_ELEMENT_ANIM_LAYER) {
  22479. ufbxi_check_err(&bc->error, ufbxi_bake_times(bc, prop->anim_value, true, 0));
  22480. has_weight_times = true;
  22481. }
  22482. }
  22483. if (has_weight_times) {
  22484. ufbxi_bake_time_list weight_times = { 0 };
  22485. ufbxi_check_err(&bc->error, ufbxi_finalize_bake_times(bc, &weight_times));
  22486. bc->layer_weight_times.count = weight_times.count;
  22487. bc->layer_weight_times.data = ufbxi_push_copy(&bc->tmp, ufbxi_bake_time, weight_times.count, weight_times.data);
  22488. ufbxi_check_err(&bc->error, bc->layer_weight_times.data);
  22489. ufbxi_buf_clear(&bc->tmp_prop);
  22490. }
  22491. }
  22492. size_t begin = 0;
  22493. while (begin < num_props) {
  22494. uint32_t element_id = props[begin].element_id;
  22495. size_t end = begin + 1;
  22496. while (end < num_props && props[end].element_id == element_id) {
  22497. end++;
  22498. }
  22499. ufbxi_check_err(&bc->error, ufbxi_bake_element(bc, element_id, props + begin, end - begin));
  22500. begin = end;
  22501. }
  22502. size_t num_nodes = bc->tmp_nodes.num_items;
  22503. size_t num_elements = bc->tmp_elements.num_items;
  22504. bc->bake.nodes.count = num_nodes;
  22505. bc->bake.nodes.data = ufbxi_push_pop(&bc->result, &bc->tmp_nodes, ufbx_baked_node, num_nodes);
  22506. ufbxi_check_err(&bc->error, bc->bake.nodes.data);
  22507. bc->bake.elements.count = num_elements;
  22508. bc->bake.elements.data = ufbxi_push_pop(&bc->result, &bc->tmp_elements, ufbx_baked_element, num_elements);
  22509. ufbxi_check_err(&bc->error, bc->bake.elements.data);
  22510. ufbxi_unstable_sort(bc->bake.nodes.data, bc->bake.nodes.count, sizeof(ufbx_baked_node), &ufbxi_baked_node_less, NULL);
  22511. ufbxi_unstable_sort(bc->bake.elements.data, bc->bake.elements.count, sizeof(ufbx_baked_element), &ufbxi_baked_element_less, NULL);
  22512. if (bc->time_min < bc->time_max) {
  22513. bc->bake.key_time_min = bc->time_min;
  22514. bc->bake.key_time_max = bc->time_max;
  22515. }
  22516. if (bc->time_begin < bc->time_end) {
  22517. bc->bake.playback_time_begin = bc->time_begin;
  22518. bc->bake.playback_time_end = bc->time_end;
  22519. bc->bake.playback_duration = bc->time_end - bc->time_begin;
  22520. }
  22521. return 1;
  22522. }
  22523. ufbxi_nodiscard static ufbxi_noinline int ufbxi_bake_anim_imp(ufbxi_bake_context *bc, const ufbx_anim *anim)
  22524. {
  22525. if (bc->opts.resample_rate <= 0.0) bc->opts.resample_rate = 30.0;
  22526. if (bc->opts.minimum_sample_rate <= 0.0) bc->opts.minimum_sample_rate = 19.5;
  22527. if (bc->opts.max_keyframe_segments == 0) bc->opts.max_keyframe_segments = 32;
  22528. if (bc->opts.key_reduction_threshold == 0) bc->opts.key_reduction_threshold = 0.000001;
  22529. if (bc->opts.key_reduction_passes == 0) bc->opts.key_reduction_passes = 4;
  22530. if (bc->opts.trim_start_time && anim->time_begin > 0.0) {
  22531. bc->ktime_offset = -anim->time_begin * (double)bc->scene->metadata.ktime_second;
  22532. }
  22533. ufbxi_init_ator(&bc->error, &bc->ator_tmp, &bc->opts.temp_allocator, "temp");
  22534. ufbxi_init_ator(&bc->error, &bc->ator_result, &bc->opts.result_allocator, "result");
  22535. bc->result.unordered = true;
  22536. bc->result.ator = &bc->ator_result;
  22537. bc->tmp.unordered = true;
  22538. bc->tmp.ator = &bc->ator_tmp;
  22539. bc->tmp_prop.ator = &bc->ator_tmp;
  22540. bc->tmp_prop.unordered = true;
  22541. bc->tmp_prop.clearable = true;
  22542. bc->tmp_times.ator = &bc->ator_tmp;
  22543. bc->tmp_bake_props.ator = &bc->ator_tmp;
  22544. bc->tmp_nodes.ator = &bc->ator_tmp;
  22545. bc->tmp_elements.ator = &bc->ator_tmp;
  22546. bc->tmp_props.ator = &bc->ator_tmp;
  22547. bc->tmp_bake_stack.ator = &bc->ator_tmp;
  22548. bc->anim = anim;
  22549. if (anim->time_begin < anim->time_end) {
  22550. bc->time_begin = anim->time_begin;
  22551. bc->time_end = anim->time_end;
  22552. }
  22553. bc->time_min = UFBX_INFINITY;
  22554. bc->time_max = -UFBX_INFINITY;
  22555. bc->imp = ufbxi_push(&bc->result, ufbxi_baked_anim_imp, 1);
  22556. ufbxi_check_err(&bc->error, bc->imp);
  22557. ufbxi_check_err(&bc->error, ufbxi_bake_anim(bc));
  22558. ufbxi_init_ref(&bc->imp->refcount, UFBXI_BAKED_ANIM_IMP_MAGIC, NULL);
  22559. bc->bake.metadata.result_memory_used = bc->ator_result.current_size;
  22560. bc->bake.metadata.temp_memory_used = bc->ator_tmp.current_size;
  22561. bc->bake.metadata.result_allocs = bc->ator_result.num_allocs;
  22562. bc->bake.metadata.temp_allocs = bc->ator_tmp.num_allocs;
  22563. bc->imp->magic = UFBXI_BAKED_ANIM_IMP_MAGIC;
  22564. bc->imp->bake = bc->bake;
  22565. bc->imp->refcount.ator = bc->ator_result;
  22566. bc->imp->refcount.buf = bc->result;
  22567. return 1;
  22568. }
  22569. #endif
  22570. // -- NURBS
  22571. static ufbxi_forceinline ufbx_real ufbxi_nurbs_weight(const ufbx_real_list *knots, size_t knot, size_t degree, ufbx_real u)
  22572. {
  22573. if (knot >= knots->count) return 0.0f;
  22574. if (knots->count - knot < degree) return 0.0f;
  22575. ufbx_real prev_u = knots->data[knot], next_u = knots->data[knot + degree];
  22576. if (prev_u >= next_u) return 0.0f;
  22577. if (u <= prev_u) return 0.0f;
  22578. if (u >= next_u) return 1.0f;
  22579. return (u - prev_u) / (next_u - prev_u);
  22580. }
  22581. static ufbxi_forceinline ufbx_real ufbxi_nurbs_deriv(const ufbx_real_list *knots, size_t knot, size_t degree)
  22582. {
  22583. if (knot >= knots->count) return 0.0f;
  22584. if (knots->count - knot < degree) return 0.0f;
  22585. ufbx_real prev_u = knots->data[knot], next_u = knots->data[knot + degree];
  22586. if (prev_u >= next_u) return 0.0f;
  22587. return (ufbx_real)degree / (next_u - prev_u);
  22588. }
  22589. typedef struct {
  22590. ufbxi_refcount refcount;
  22591. ufbx_line_curve curve;
  22592. uint32_t magic;
  22593. } ufbxi_line_curve_imp;
  22594. ufbx_static_assert(line_curve_imp_offset, offsetof(ufbxi_line_curve_imp, curve) == sizeof(ufbxi_refcount));
  22595. #if UFBXI_FEATURE_TESSELLATION
  22596. typedef struct {
  22597. ufbx_error error;
  22598. ufbx_tessellate_curve_opts opts;
  22599. const ufbx_nurbs_curve *curve;
  22600. ufbxi_allocator ator_tmp;
  22601. ufbxi_allocator ator_result;
  22602. ufbxi_buf result;
  22603. ufbx_line_curve line;
  22604. ufbxi_line_curve_imp *imp;
  22605. } ufbxi_tessellate_curve_context;
  22606. typedef struct {
  22607. ufbx_error error;
  22608. ufbx_tessellate_surface_opts opts;
  22609. const ufbx_nurbs_surface *surface;
  22610. ufbxi_allocator ator_tmp;
  22611. ufbxi_allocator ator_result;
  22612. ufbxi_buf tmp;
  22613. ufbxi_buf result;
  22614. ufbxi_map position_map;
  22615. ufbx_mesh mesh;
  22616. ufbxi_mesh_imp *imp;
  22617. } ufbxi_tessellate_surface_context;
  22618. ufbxi_nodiscard static ufbxi_noinline int ufbxi_tessellate_nurbs_curve_imp(ufbxi_tessellate_curve_context *tc)
  22619. {
  22620. if (tc->opts.span_subdivision <= 0) {
  22621. tc->opts.span_subdivision = 4;
  22622. }
  22623. size_t num_sub = tc->opts.span_subdivision;
  22624. const ufbx_nurbs_curve *curve = tc->curve;
  22625. ufbx_line_curve *line = &tc->line;
  22626. ufbxi_check_err_msg(&tc->error, curve->basis.valid && curve->control_points.count > 0, "Bad NURBS geometry");
  22627. ufbxi_init_ator(&tc->error, &tc->ator_tmp, &tc->opts.temp_allocator, "temp");
  22628. ufbxi_init_ator(&tc->error, &tc->ator_result, &tc->opts.result_allocator, "result");
  22629. tc->result.unordered = true;
  22630. tc->result.ator = &tc->ator_result;
  22631. size_t num_spans = curve->basis.spans.count;
  22632. // Check conservatively that we don't overflow anything
  22633. {
  22634. size_t over_spans = num_spans * 2 * sizeof(ufbx_real);
  22635. size_t over = over_spans * num_sub;
  22636. ufbxi_check_err(&tc->error, !ufbxi_does_overflow(over, over_spans, num_sub));
  22637. }
  22638. bool is_open = curve->basis.topology == UFBX_NURBS_TOPOLOGY_OPEN;
  22639. size_t num_indices = num_spans + (num_spans - 1) * (num_sub - 1);
  22640. size_t num_vertices = num_indices - (is_open ? 0u : 1u);
  22641. ufbxi_check_err(&tc->error, num_indices <= INT32_MAX);
  22642. uint32_t *indices = ufbxi_push(&tc->result, uint32_t, num_indices);
  22643. ufbx_vec3 *vertices = ufbxi_push(&tc->result, ufbx_vec3, num_vertices);
  22644. ufbx_line_segment *segments = ufbxi_push(&tc->result, ufbx_line_segment, 1);
  22645. ufbxi_check_err(&tc->error, indices && vertices && segments);
  22646. for (size_t span_ix = 0; span_ix < num_spans; span_ix++) {
  22647. size_t num_splits = span_ix + 1 == num_spans ? 1 : num_sub;
  22648. for (size_t sub_ix = 0; sub_ix < num_splits; sub_ix++) {
  22649. size_t ix = span_ix * num_sub + sub_ix;
  22650. if (ix < num_vertices) {
  22651. ufbx_real u = curve->basis.spans.data[span_ix];
  22652. if (sub_ix > 0) {
  22653. ufbx_real t = (ufbx_real)sub_ix / (ufbx_real)num_sub;
  22654. u = u * (1.0f - t) + t * curve->basis.spans.data[span_ix + 1];
  22655. }
  22656. ufbx_curve_point point = ufbx_evaluate_nurbs_curve(curve, u);
  22657. vertices[ix] = point.position;
  22658. indices[ix] = (uint32_t)ix;
  22659. } else {
  22660. indices[ix] = 0;
  22661. }
  22662. }
  22663. }
  22664. segments[0].index_begin = 0;
  22665. segments[0].num_indices = (uint32_t)num_indices;
  22666. line->element.name.data = ufbxi_empty_char;
  22667. line->element.type = UFBX_ELEMENT_LINE_CURVE;
  22668. line->element.typed_id = UINT32_MAX;
  22669. line->element.element_id = UINT32_MAX;
  22670. line->color.x = 1.0f;
  22671. line->color.y = 1.0f;
  22672. line->color.z = 1.0f;
  22673. line->control_points.data = vertices;
  22674. line->control_points.count = num_vertices;
  22675. line->point_indices.data = indices;
  22676. line->point_indices.count = num_indices;
  22677. line->segments.data = segments;
  22678. line->segments.count = 1;
  22679. line->from_tessellated_nurbs = true;
  22680. tc->imp = ufbxi_push(&tc->result, ufbxi_line_curve_imp, 1);
  22681. ufbxi_check_err(&tc->error, tc->imp);
  22682. ufbxi_init_ref(&tc->imp->refcount, UFBXI_LINE_CURVE_IMP_MAGIC, &(ufbxi_get_imp(ufbxi_scene_imp, curve->element.scene))->refcount);
  22683. tc->imp->magic = UFBXI_LINE_CURVE_IMP_MAGIC;
  22684. tc->imp->curve = tc->line;
  22685. tc->imp->refcount.ator = tc->ator_result;
  22686. tc->imp->refcount.buf = tc->result;
  22687. return 1;
  22688. }
  22689. ufbxi_nodiscard static ufbxi_noinline int ufbxi_tessellate_nurbs_surface_imp(ufbxi_tessellate_surface_context *tc)
  22690. {
  22691. if (tc->opts.span_subdivision_u <= 0) {
  22692. tc->opts.span_subdivision_u = 4;
  22693. }
  22694. if (tc->opts.span_subdivision_v <= 0) {
  22695. tc->opts.span_subdivision_v = 4;
  22696. }
  22697. size_t sub_u = tc->opts.span_subdivision_u;
  22698. size_t sub_v = tc->opts.span_subdivision_v;
  22699. const ufbx_nurbs_surface *surface = tc->surface;
  22700. ufbx_mesh *mesh = &tc->mesh;
  22701. ufbxi_check_err_msg(&tc->error, surface->basis_u.valid && surface->basis_v.valid
  22702. && surface->num_control_points_u > 0 && surface->num_control_points_v > 0, "Bad NURBS geometry");
  22703. ufbxi_init_ator(&tc->error, &tc->ator_tmp, &tc->opts.temp_allocator, "temp");
  22704. ufbxi_init_ator(&tc->error, &tc->ator_result, &tc->opts.result_allocator, "result");
  22705. tc->result.unordered = true;
  22706. tc->tmp.unordered = true;
  22707. tc->result.ator = &tc->ator_result;
  22708. tc->tmp.ator = &tc->ator_tmp;
  22709. bool open_u = surface->basis_u.topology == UFBX_NURBS_TOPOLOGY_OPEN;
  22710. bool open_v = surface->basis_v.topology == UFBX_NURBS_TOPOLOGY_OPEN;
  22711. size_t spans_u = surface->basis_u.spans.count;
  22712. size_t spans_v = surface->basis_v.spans.count;
  22713. // Check conservatively that we don't overflow anything
  22714. {
  22715. size_t over_spans_u = spans_u * 2 * sizeof(ufbx_real);
  22716. size_t over_spans_v = spans_v * 2 * sizeof(ufbx_real);
  22717. size_t over_u = over_spans_u * sub_u;
  22718. size_t over_v = over_spans_v * sub_v;
  22719. size_t over_uv = over_u * over_v;
  22720. ufbxi_check_err(&tc->error, !ufbxi_does_overflow(over_u, over_spans_u, sub_u));
  22721. ufbxi_check_err(&tc->error, !ufbxi_does_overflow(over_v, over_spans_v, sub_v));
  22722. ufbxi_check_err(&tc->error, !ufbxi_does_overflow(over_uv, over_u, over_v));
  22723. }
  22724. size_t faces_u = (spans_u - 1) * sub_u;
  22725. size_t faces_v = (spans_v - 1) * sub_v;
  22726. size_t indices_u = spans_u + (spans_u - 1) * (sub_u - 1);
  22727. size_t indices_v = spans_v + (spans_v - 1) * (sub_v - 1);
  22728. size_t num_faces = faces_u * faces_v;
  22729. size_t num_indices = indices_u * indices_v;
  22730. ufbxi_check_err(&tc->error, num_indices <= INT32_MAX);
  22731. uint32_t *position_ix = ufbxi_push(&tc->tmp, uint32_t, num_indices);
  22732. ufbx_vec3 *positions = ufbxi_push(&tc->result, ufbx_vec3, num_indices + 1);
  22733. ufbx_vec3 *normals = ufbxi_push(&tc->result, ufbx_vec3, num_indices + 1);
  22734. ufbx_vec2 *uvs = ufbxi_push(&tc->result, ufbx_vec2, num_indices + 1);
  22735. ufbx_vec3 *tangents = ufbxi_push(&tc->result, ufbx_vec3, num_indices + 1);
  22736. ufbx_vec3 *bitangents = ufbxi_push(&tc->result, ufbx_vec3, num_indices + 1);
  22737. ufbxi_check_err(&tc->error, position_ix && uvs && tangents && bitangents);
  22738. *positions++ = ufbx_zero_vec3;
  22739. *normals++ = ufbx_zero_vec3;
  22740. *uvs++ = ufbx_zero_vec2;
  22741. *tangents++ = ufbx_zero_vec3;
  22742. *bitangents++ = ufbx_zero_vec3;
  22743. uint32_t num_positions = 0;
  22744. for (size_t span_v = 0; span_v < spans_v; span_v++) {
  22745. size_t splits_v = span_v + 1 == spans_v ? 1 : sub_v;
  22746. for (size_t split_v = 0; split_v < splits_v; split_v++) {
  22747. size_t ix_v = span_v * sub_v + split_v;
  22748. ufbx_assert(ix_v < indices_v);
  22749. ufbx_real v = surface->basis_v.spans.data[span_v];
  22750. if (split_v > 0) {
  22751. ufbx_real t = (ufbx_real)split_v / (ufbx_real)splits_v;
  22752. v = v * (1.0f - t) + t * surface->basis_v.spans.data[span_v + 1];
  22753. }
  22754. ufbx_real original_v = v;
  22755. if (span_v + 1 == spans_v && !open_v) {
  22756. v = surface->basis_v.spans.data[0];
  22757. }
  22758. for (size_t span_u = 0; span_u < spans_u; span_u++) {
  22759. size_t splits_u = span_u + 1 == spans_u ? 1 : sub_u;
  22760. for (size_t split_u = 0; split_u < splits_u; split_u++) {
  22761. size_t ix_u = span_u * sub_u + split_u;
  22762. ufbx_assert(ix_u < indices_u);
  22763. ufbx_real u = surface->basis_u.spans.data[span_u];
  22764. if (split_u > 0) {
  22765. ufbx_real t = (ufbx_real)split_u / (ufbx_real)splits_u;
  22766. u = u * (1.0f - t) + t * surface->basis_u.spans.data[span_u + 1];
  22767. }
  22768. ufbx_real original_u = u;
  22769. if (span_u + 1 == spans_u && !open_u) {
  22770. u = surface->basis_u.spans.data[0];
  22771. }
  22772. ufbx_surface_point point = ufbx_evaluate_nurbs_surface(surface, u, v);
  22773. ufbx_vec3 pos = point.position;
  22774. ufbx_vec3 tangent_u = ufbxi_slow_normalize3(&point.derivative_u);
  22775. ufbx_vec3 tangent_v = ufbxi_slow_normalize3(&point.derivative_v);
  22776. // Check if there's any wrapped positions that we could match
  22777. size_t neighbors[5]; // ufbxi_uninit
  22778. size_t num_neighbors = 0;
  22779. if ((span_v == 0 && (span_u > 0 || split_u > 0)) || (span_u == 0 && (span_v > 0 || split_v > 0))) {
  22780. // Top/left
  22781. neighbors[num_neighbors++] = 0;
  22782. }
  22783. if (span_v + 1 == spans_v) {
  22784. // Bottom
  22785. neighbors[num_neighbors++] = ix_u;
  22786. if (span_u > 0 || split_u > 0) {
  22787. neighbors[num_neighbors++] = ix_v * indices_u;
  22788. }
  22789. }
  22790. if (span_u + 1 == spans_u) {
  22791. // Right
  22792. neighbors[num_neighbors++] = ix_v * indices_u;
  22793. if (span_v > 0 || split_v > 0) {
  22794. neighbors[num_neighbors++] = indices_u - 1;
  22795. }
  22796. }
  22797. size_t ix = ix_v * indices_u + ix_u;
  22798. uint32_t pos_ix = num_positions;
  22799. for (size_t i = 0; i < num_neighbors; i++) {
  22800. size_t nb_ix = neighbors[i];
  22801. ufbx_assert(nb_ix < ix);
  22802. uint32_t nb_pos_ix = position_ix[nb_ix];
  22803. ufbx_vec3 nb_pos = positions[nb_pos_ix];
  22804. ufbx_real dx = nb_pos.x - pos.x;
  22805. ufbx_real dy = nb_pos.y - pos.y;
  22806. ufbx_real dz = nb_pos.z - pos.z;
  22807. ufbx_real delta = dx*dx + dy*dy + dz*dz;
  22808. if (delta < 0.0000001f) { // TODO: Configurable / something more rigorous
  22809. pos_ix = nb_pos_ix;
  22810. break;
  22811. }
  22812. }
  22813. position_ix[ix] = pos_ix;
  22814. if (pos_ix == num_positions) {
  22815. positions[pos_ix] = pos;
  22816. num_positions = pos_ix + 1;
  22817. }
  22818. uvs[ix].x = original_u;
  22819. uvs[ix].y = original_v;
  22820. tangents[ix] = tangent_u;
  22821. bitangents[ix] = tangent_v;
  22822. }
  22823. }
  22824. }
  22825. }
  22826. ufbx_face *faces = ufbxi_push(&tc->result, ufbx_face, num_faces);
  22827. uint32_t *vertex_ix = ufbxi_push(&tc->result, uint32_t, num_faces * 4);
  22828. uint32_t *attrib_ix = ufbxi_push(&tc->result, uint32_t, num_faces * 4);
  22829. ufbxi_check_err(&tc->error, faces && vertex_ix && attrib_ix);
  22830. size_t face_ix = 0;
  22831. size_t dst_index = 0;
  22832. size_t num_triangles = 0;
  22833. for (size_t face_v = 0; face_v < faces_v; face_v++) {
  22834. for (size_t face_u = 0; face_u < faces_u; face_u++) {
  22835. attrib_ix[dst_index + 0] = (uint32_t)((face_v + 0) * indices_u + (face_u + 0));
  22836. attrib_ix[dst_index + 1] = (uint32_t)((face_v + 0) * indices_u + (face_u + 1));
  22837. attrib_ix[dst_index + 2] = (uint32_t)((face_v + 1) * indices_u + (face_u + 1));
  22838. attrib_ix[dst_index + 3] = (uint32_t)((face_v + 1) * indices_u + (face_u + 0));
  22839. vertex_ix[dst_index + 0] = position_ix[attrib_ix[dst_index + 0]];
  22840. vertex_ix[dst_index + 1] = position_ix[attrib_ix[dst_index + 1]];
  22841. vertex_ix[dst_index + 2] = position_ix[attrib_ix[dst_index + 2]];
  22842. vertex_ix[dst_index + 3] = position_ix[attrib_ix[dst_index + 3]];
  22843. bool is_triangle = false;
  22844. for (size_t prev_ix = 0; prev_ix < 4; prev_ix++) {
  22845. size_t next_ix = (prev_ix + 1) % 4;
  22846. if (vertex_ix[dst_index + prev_ix] == vertex_ix[dst_index + next_ix]) {
  22847. for (size_t i = next_ix; i < 3; i++) {
  22848. attrib_ix[dst_index + i] = attrib_ix[dst_index + i + 1];
  22849. vertex_ix[dst_index + i] = vertex_ix[dst_index + i + 1];
  22850. }
  22851. is_triangle = true;
  22852. break;
  22853. }
  22854. }
  22855. faces[face_ix].index_begin = (uint32_t)dst_index;
  22856. faces[face_ix].num_indices = is_triangle ? 3 : 4;
  22857. dst_index += is_triangle ? 3 : 4;
  22858. num_triangles += is_triangle ? 1 : 2;
  22859. face_ix++;
  22860. }
  22861. }
  22862. ufbxi_check_err(&tc->error, positions && normals);
  22863. mesh->element.name.data = ufbxi_empty_char;
  22864. mesh->element.type = UFBX_ELEMENT_MESH;
  22865. mesh->element.typed_id = UINT32_MAX;
  22866. mesh->element.element_id = UINT32_MAX;
  22867. mesh->vertices.data = positions;
  22868. mesh->vertices.count = num_positions;
  22869. mesh->num_vertices = num_positions;
  22870. mesh->vertex_indices.data = vertex_ix;
  22871. mesh->vertex_indices.count = dst_index;
  22872. mesh->faces.data = faces;
  22873. mesh->faces.count = num_faces;
  22874. mesh->vertex_position.exists = true;
  22875. mesh->vertex_position.values.data = positions;
  22876. mesh->vertex_position.values.count = num_positions;
  22877. mesh->vertex_position.indices.data = vertex_ix;
  22878. mesh->vertex_position.indices.count = dst_index;
  22879. mesh->vertex_position.unique_per_vertex = true;
  22880. mesh->vertex_uv.exists = true;
  22881. mesh->vertex_uv.values.data = uvs;
  22882. mesh->vertex_uv.values.count = dst_index;
  22883. mesh->vertex_uv.indices.data = attrib_ix;
  22884. mesh->vertex_uv.indices.count = dst_index;
  22885. mesh->vertex_normal.exists = true;
  22886. mesh->vertex_normal.values.data = normals;
  22887. mesh->vertex_normal.values.count = num_positions;
  22888. mesh->vertex_normal.indices.data = vertex_ix;
  22889. mesh->vertex_normal.indices.count = dst_index;
  22890. mesh->vertex_tangent.exists = true;
  22891. mesh->vertex_tangent.values.data = tangents;
  22892. mesh->vertex_tangent.values.count = dst_index;
  22893. mesh->vertex_tangent.indices.data = attrib_ix;
  22894. mesh->vertex_tangent.indices.count = dst_index;
  22895. mesh->vertex_bitangent.exists = true;
  22896. mesh->vertex_bitangent.values.data = bitangents;
  22897. mesh->vertex_bitangent.values.count = dst_index;
  22898. mesh->vertex_bitangent.indices.data = attrib_ix;
  22899. mesh->vertex_bitangent.indices.count = dst_index;
  22900. mesh->num_faces = num_faces;
  22901. mesh->num_triangles = num_triangles;
  22902. mesh->num_indices = dst_index;
  22903. mesh->max_face_triangles = 2;
  22904. if (surface->material) {
  22905. mesh->face_material.data = ufbxi_push_zero(&tc->result, uint32_t, num_faces);
  22906. ufbxi_check_err(&tc->error, mesh->face_material.data);
  22907. ufbx_material **mat = ufbxi_push_zero(&tc->result, ufbx_material*, 1);
  22908. ufbxi_check_err(&tc->error, mat);
  22909. *mat = surface->material;
  22910. mesh->materials.data = mat;
  22911. mesh->materials.count = 1;
  22912. }
  22913. if (!tc->opts.skip_mesh_parts) {
  22914. mesh->material_parts.count = 1;
  22915. mesh->material_parts.data = ufbxi_push_zero(&tc->result, ufbx_mesh_part, 1);
  22916. ufbxi_check_err(&tc->error, mesh->material_parts.data);
  22917. }
  22918. ufbxi_check_err(&tc->error, ufbxi_finalize_mesh_material(&tc->result, &tc->error, mesh));
  22919. ufbxi_check_err(&tc->error, ufbxi_finalize_mesh(&tc->result, &tc->error, mesh));
  22920. mesh->generated_normals = true;
  22921. ufbx_compute_normals(mesh, &mesh->vertex_position,
  22922. mesh->vertex_normal.indices.data, mesh->vertex_normal.indices.count,
  22923. mesh->vertex_normal.values.data, mesh->vertex_normal.values.count);
  22924. if (surface->flip_normals) {
  22925. ufbxi_nounroll ufbxi_for_list(ufbx_vec3, normal, mesh->vertex_normal.values) {
  22926. normal->x *= -1.0f;
  22927. normal->y *= -1.0f;
  22928. normal->z *= -1.0f;
  22929. }
  22930. }
  22931. tc->imp = ufbxi_push(&tc->result, ufbxi_mesh_imp, 1);
  22932. ufbxi_check_err(&tc->error, tc->imp);
  22933. ufbxi_init_ref(&tc->imp->refcount, UFBXI_MESH_IMP_MAGIC, &(ufbxi_get_imp(ufbxi_scene_imp, surface->element.scene))->refcount);
  22934. tc->imp->magic = UFBXI_MESH_IMP_MAGIC;
  22935. tc->imp->mesh = tc->mesh;
  22936. tc->imp->refcount.ator = tc->ator_result;
  22937. tc->imp->refcount.buf = tc->result;
  22938. tc->imp->mesh.subdivision_evaluated = true;
  22939. return 1;
  22940. }
  22941. #endif
  22942. // -- Topology
  22943. #if UFBXI_FEATURE_KD
  22944. typedef struct {
  22945. ufbx_real split;
  22946. uint32_t index_plus_one; // 0 for empty
  22947. uint32_t slow_left;
  22948. uint32_t slow_right;
  22949. uint32_t slow_end;
  22950. } ufbxi_kd_node;
  22951. typedef struct {
  22952. ufbx_face face;
  22953. ufbx_vertex_vec3 positions;
  22954. ufbx_vec3 axes[3];
  22955. ufbxi_kd_node kd_nodes[1 << (UFBXI_KD_FAST_DEPTH + 1)];
  22956. uint32_t *kd_indices;
  22957. // Temporary
  22958. ufbx_vec3 cur_axis_dir;
  22959. ufbx_face cur_face;
  22960. } ufbxi_ngon_context;
  22961. typedef struct {
  22962. ufbx_real min_t[2];
  22963. ufbx_real max_t[2];
  22964. ufbx_vec2 points[3];
  22965. uint32_t indices[3];
  22966. } ufbxi_kd_triangle;
  22967. ufbxi_noinline static ufbx_vec2 ufbxi_ngon_project(ufbxi_ngon_context *nc, uint32_t index)
  22968. {
  22969. ufbx_vec3 point = nc->positions.values.data[nc->positions.indices.data[nc->face.index_begin + index]];
  22970. ufbx_vec2 p;
  22971. p.x = ufbxi_dot3(nc->axes[0], point);
  22972. p.y = ufbxi_dot3(nc->axes[1], point);
  22973. return p;
  22974. }
  22975. ufbxi_forceinline static ufbx_real ufbxi_orient2d(ufbx_vec2 a, ufbx_vec2 b, ufbx_vec2 c)
  22976. {
  22977. return (b.x - a.x)*(c.y - a.y) - (b.y - a.y)*(c.x - a.x);
  22978. }
  22979. ufbxi_noinline static bool ufbxi_kd_check_point(ufbxi_ngon_context *nc, const ufbxi_kd_triangle *tri, uint32_t index)
  22980. {
  22981. if (index == tri->indices[0] || index == tri->indices[1] || index == tri->indices[2]) return false;
  22982. ufbx_vec2 p = ufbxi_ngon_project(nc, index);
  22983. ufbx_real u = ufbxi_orient2d(p, tri->points[0], tri->points[1]);
  22984. ufbx_real v = ufbxi_orient2d(p, tri->points[1], tri->points[2]);
  22985. ufbx_real w = ufbxi_orient2d(p, tri->points[2], tri->points[0]);
  22986. if (u <= 0.0f && v <= 0.0f && w <= 0.0f) return true;
  22987. if (u >= 0.0f && v >= 0.0f && w >= 0.0f) return true;
  22988. return false;
  22989. }
  22990. // Recursion limited by 32-bit indices in input, minus halvings from `ufbxi_kd_check_fast()`
  22991. ufbxi_noinline static bool ufbxi_kd_check_slow(ufbxi_ngon_context *nc, const ufbxi_kd_triangle *tri, uint32_t begin, uint32_t count, uint32_t axis)
  22992. ufbxi_recursive_function(bool, ufbxi_kd_check_slow, (nc, tri, begin, count, axis), 32 - UFBXI_KD_FAST_DEPTH,
  22993. (ufbxi_ngon_context *nc, const ufbxi_kd_triangle *tri, uint32_t begin, uint32_t count, uint32_t axis))
  22994. {
  22995. ufbx_vertex_vec3 pos = nc->positions;
  22996. uint32_t *kd_indices = nc->kd_indices;
  22997. while (count > 0) {
  22998. uint32_t num_left = count / 2;
  22999. uint32_t begin_right = begin + num_left + 1;
  23000. uint32_t num_right = count - (num_left + 1);
  23001. uint32_t index = kd_indices[begin + num_left];
  23002. ufbx_vec3 point = pos.values.data[pos.indices.data[nc->face.index_begin + index]];
  23003. ufbx_real split = ufbxi_dot3(point, nc->axes[axis]);
  23004. bool hit_left = tri->min_t[axis] <= split;
  23005. bool hit_right = tri->max_t[axis] >= split;
  23006. if (hit_left && hit_right) {
  23007. if (ufbxi_kd_check_point(nc, tri, index)) {
  23008. return true;
  23009. }
  23010. if (ufbxi_kd_check_slow(nc, tri, begin_right, num_right, axis ^ 1)) {
  23011. return true;
  23012. }
  23013. }
  23014. axis ^= 1;
  23015. if (hit_left) {
  23016. count = num_left;
  23017. } else {
  23018. begin = begin_right;
  23019. count = num_right;
  23020. }
  23021. }
  23022. return false;
  23023. }
  23024. // Recursion limited by `UFBXI_KD_FAST_DEPTH`
  23025. ufbxi_noinline static bool ufbxi_kd_check_fast(ufbxi_ngon_context *nc, const ufbxi_kd_triangle *tri, uint32_t kd_index, uint32_t axis, uint32_t depth)
  23026. ufbxi_recursive_function(bool, ufbxi_kd_check_fast, (nc, tri, kd_index, axis, depth), UFBXI_KD_FAST_DEPTH,
  23027. (ufbxi_ngon_context *nc, const ufbxi_kd_triangle *tri, uint32_t kd_index, uint32_t axis, uint32_t depth))
  23028. {
  23029. for (;;) {
  23030. ufbxi_kd_node node = nc->kd_nodes[kd_index];
  23031. if (node.index_plus_one == 0) return false;
  23032. bool hit_left = tri->min_t[axis] <= node.split;
  23033. bool hit_right = tri->max_t[axis] >= node.split;
  23034. uint32_t side = hit_left ? 0 : 1;
  23035. uint32_t child_kd_index = kd_index * 2 + 1 + side;
  23036. if (hit_left && hit_right) {
  23037. // Check for the point on the split plane
  23038. uint32_t index = node.index_plus_one - 1;
  23039. if (ufbxi_kd_check_point(nc, tri, index)) {
  23040. return true;
  23041. }
  23042. // Recurse always to the right if we hit both sides
  23043. if (depth + 1 == UFBXI_KD_FAST_DEPTH) {
  23044. if (ufbxi_kd_check_slow(nc, tri, node.slow_right, node.slow_end - node.slow_right, axis ^ 1)) {
  23045. return true;
  23046. }
  23047. } else {
  23048. if (ufbxi_kd_check_fast(nc, tri, child_kd_index + 1, axis ^ 1, depth + 1)) {
  23049. return true;
  23050. }
  23051. }
  23052. }
  23053. depth++;
  23054. axis ^= 1;
  23055. kd_index = child_kd_index;
  23056. if (depth == UFBXI_KD_FAST_DEPTH) {
  23057. if (hit_left) {
  23058. return ufbxi_kd_check_slow(nc, tri, node.slow_left, node.slow_right - node.slow_left, axis);
  23059. } else {
  23060. return ufbxi_kd_check_slow(nc, tri, node.slow_right, node.slow_end - node.slow_right, axis);
  23061. }
  23062. }
  23063. }
  23064. }
  23065. ufbxi_noinline static bool ufbxi_kd_check(ufbxi_ngon_context *nc, const ufbx_vec2 *points, const uint32_t *indices)
  23066. {
  23067. ufbxi_kd_triangle tri; // ufbxi_uninit
  23068. tri.points[0] = points[0];
  23069. tri.points[1] = points[1];
  23070. tri.points[2] = points[2];
  23071. tri.indices[0] = indices[0];
  23072. tri.indices[1] = indices[1];
  23073. tri.indices[2] = indices[2];
  23074. tri.min_t[0] = ufbxi_min_real(ufbxi_min_real(points[0].x, points[1].x), points[2].x);
  23075. tri.min_t[1] = ufbxi_min_real(ufbxi_min_real(points[0].y, points[1].y), points[2].y);
  23076. tri.max_t[0] = ufbxi_max_real(ufbxi_max_real(points[0].x, points[1].x), points[2].x);
  23077. tri.max_t[1] = ufbxi_max_real(ufbxi_max_real(points[0].y, points[1].y), points[2].y);
  23078. return ufbxi_kd_check_fast(nc, &tri, 0, 0, 0);
  23079. }
  23080. ufbxi_noinline static bool ufbxi_kd_index_less(void *user, const void *va, const void *vb)
  23081. {
  23082. ufbxi_ngon_context *nc = (ufbxi_ngon_context*)user;
  23083. ufbx_vertex_vec3 *pos = &nc->positions;
  23084. const uint32_t a = *(const uint32_t*)va, b = *(const uint32_t*)vb;
  23085. ufbx_real da = ufbxi_dot3(nc->cur_axis_dir, pos->values.data[pos->indices.data[nc->cur_face.index_begin + a]]);
  23086. ufbx_real db = ufbxi_dot3(nc->cur_axis_dir, pos->values.data[pos->indices.data[nc->cur_face.index_begin + b]]);
  23087. return da < db;
  23088. }
  23089. // Recursion limited by 32-bit indices in input
  23090. ufbxi_noinline static void ufbxi_kd_build(ufbxi_ngon_context *nc, uint32_t *indices, uint32_t *tmp, uint32_t num, uint32_t axis, uint32_t fast_index, uint32_t depth)
  23091. ufbxi_recursive_function_void(ufbxi_kd_build, (nc, indices, tmp, num, axis, fast_index, depth), 32,
  23092. (ufbxi_ngon_context *nc, uint32_t *indices, uint32_t *tmp, uint32_t num, uint32_t axis, uint32_t fast_index, uint32_t depth))
  23093. {
  23094. if (num == 0) return;
  23095. ufbx_vertex_vec3 pos = nc->positions;
  23096. ufbx_vec3 axis_dir = nc->axes[axis];
  23097. ufbx_face face = nc->face;
  23098. nc->cur_axis_dir = axis_dir;
  23099. nc->cur_face = face;
  23100. // Sort the remaining indices based on the axis
  23101. ufbxi_stable_sort(sizeof(uint32_t), 16, indices, tmp, num, &ufbxi_kd_index_less, nc);
  23102. uint32_t num_left = num / 2;
  23103. uint32_t begin_right = num_left + 1;
  23104. uint32_t num_right = num - begin_right;
  23105. uint32_t dst_right = num_left + 1;
  23106. if (depth < UFBXI_KD_FAST_DEPTH) {
  23107. uint32_t skip_left = 1u << (UFBXI_KD_FAST_DEPTH - depth - 1);
  23108. dst_right = dst_right > skip_left ? dst_right - skip_left : 0;
  23109. uint32_t index = indices[num_left];
  23110. ufbxi_kd_node *kd = &nc->kd_nodes[fast_index];
  23111. kd->split = ufbxi_dot3(axis_dir, pos.values.data[pos.indices.data[face.index_begin + index]]);
  23112. kd->index_plus_one = index + 1;
  23113. if (depth + 1 == UFBXI_KD_FAST_DEPTH) {
  23114. kd->slow_left = (uint32_t)(indices - nc->kd_indices);
  23115. kd->slow_right = kd->slow_left + num_left;
  23116. kd->slow_end = kd->slow_right + num_right;
  23117. } else {
  23118. kd->slow_left = UINT32_MAX;
  23119. kd->slow_right = UINT32_MAX;
  23120. kd->slow_end = UINT32_MAX;
  23121. }
  23122. }
  23123. uint32_t child_fast = fast_index * 2 + 1;
  23124. ufbxi_kd_build(nc, indices, tmp, num_left, axis ^ 1, child_fast + 0, depth + 1);
  23125. if (dst_right != begin_right) {
  23126. memmove(indices + dst_right, indices + begin_right, num_right * sizeof(uint32_t));
  23127. }
  23128. ufbxi_kd_build(nc, indices + dst_right, tmp, num_right, axis ^ 1, child_fast + 1, depth + 1);
  23129. }
  23130. #endif
  23131. #if UFBXI_FEATURE_TRIANGULATION
  23132. ufbxi_noinline static ufbx_real ufbxi_ngon_tri_weight(const ufbx_vec2 *points)
  23133. {
  23134. ufbx_vec2 p0 = points[0], p1 = points[1], p2 = points[2];
  23135. ufbx_real orient = ufbxi_orient2d(p0, p1, p2);
  23136. if (orient <= 0.0f) return -1.0f;
  23137. ufbx_real a = ufbxi_distsq2(p0, p1);
  23138. ufbx_real b = ufbxi_distsq2(p1, p2);
  23139. ufbx_real c = ufbxi_distsq2(p2, p0);
  23140. ufbx_real ab = (a + b - c) / (ufbx_real)ufbx_sqrt(4.0f * a * b);
  23141. ufbx_real bc = (b + c - a) / (ufbx_real)ufbx_sqrt(4.0f * b * c);
  23142. ufbx_real ca = (c + a - b) / (ufbx_real)ufbx_sqrt(4.0f * c * a);
  23143. return (ufbx_real)ufbx_fmax(UFBX_EPSILON, 2.0f - ufbx_fmax(ufbx_fmax(ab, bc), ca));
  23144. }
  23145. ufbxi_noinline static uint32_t ufbxi_triangulate_ngon(ufbxi_ngon_context *nc, uint32_t *indices, uint32_t num_indices)
  23146. {
  23147. ufbx_face face = nc->face;
  23148. ufbx_assert(face.num_indices > 4);
  23149. // Form an orthonormal basis to project the polygon into a 2D plane
  23150. ufbx_vec3 normal = ufbx_get_weighted_face_normal(&nc->positions, face);
  23151. ufbx_real len = ufbxi_length3(normal);
  23152. if (len > UFBX_EPSILON) {
  23153. normal = ufbxi_mul3(normal, 1.0f / len);
  23154. } else {
  23155. normal.x = 1.0f;
  23156. normal.y = 0.0f;
  23157. normal.z = 0.0f;
  23158. }
  23159. ufbx_vec3 axis; // ufbxi_uninit
  23160. if (normal.x*normal.x < 0.5f) {
  23161. axis.x = 1.0f;
  23162. axis.y = 0.0f;
  23163. axis.z = 0.0f;
  23164. } else {
  23165. axis.x = 0.0f;
  23166. axis.y = 1.0f;
  23167. axis.z = 0.0f;
  23168. }
  23169. nc->axes[0] = ufbxi_slow_normalized_cross3(&axis, &normal);
  23170. nc->axes[1] = ufbxi_slow_normalized_cross3(&normal, &nc->axes[0]);
  23171. nc->axes[2] = normal;
  23172. uint32_t *kd_indices = indices;
  23173. nc->kd_indices = kd_indices;
  23174. uint32_t *kd_tmp = indices + face.num_indices;
  23175. // Collect all the reflex corners for intersection testing.
  23176. uint32_t num_kd_indices = 0;
  23177. {
  23178. ufbx_vec2 a = ufbxi_ngon_project(nc, face.num_indices - 1);
  23179. ufbx_vec2 b = ufbxi_ngon_project(nc, 0);
  23180. for (uint32_t i = 0; i < face.num_indices; i++) {
  23181. uint32_t next = i + 1 < face.num_indices ? i + 1 : 0;
  23182. ufbx_vec2 c = ufbxi_ngon_project(nc, next);
  23183. if (ufbxi_orient2d(a, b, c) <= 0.0f) {
  23184. kd_indices[num_kd_indices++] = i;
  23185. }
  23186. a = b;
  23187. b = c;
  23188. }
  23189. }
  23190. // Build a KD-tree of the vertices.
  23191. uint32_t num_skip_indices = (1u << (UFBXI_KD_FAST_DEPTH + 1)) - 1;
  23192. uint32_t kd_slow_indices = num_kd_indices > num_skip_indices ? num_kd_indices - num_skip_indices : 0;
  23193. ufbxi_ignore(kd_slow_indices);
  23194. ufbx_assert(kd_slow_indices + face.num_indices * 2 <= num_indices);
  23195. ufbxi_kd_build(nc, kd_indices, kd_tmp, num_kd_indices, 0, 0, 0);
  23196. uint32_t *edges = indices + num_indices - face.num_indices * 2;
  23197. // Initialize `edges` to be a connectivity structure where:
  23198. // `edges[2*i + 0]` is the previous vertex of `i`
  23199. // `edges[2*i + 1]` is the next vertex of `i`
  23200. // When clipped we mark indices with the high bit (0x80000000)
  23201. for (uint32_t i = 0; i < face.num_indices; i++) {
  23202. edges[i*2 + 0] = i > 0 ? i - 1 : face.num_indices - 1;
  23203. edges[i*2 + 1] = i + 1 < face.num_indices ? i + 1 : 0;
  23204. }
  23205. // Core of the ear clipping algorithm.
  23206. // Iterate through the polygon corners looking for potential ears satisfying:
  23207. // - Angle must be less than 180deg
  23208. // - The triangle formed by the two edges must be contained within the polygon
  23209. // As these properties change only locally between modifications we only need
  23210. // to iterate the polygon once if we move backwards one step every time we clip an ear.
  23211. uint32_t indices_left = face.num_indices;
  23212. {
  23213. uint32_t point_indices[4] = { 0, 1, 2, 3 };
  23214. ufbx_real weights[2]; // ufbxi_uninit
  23215. ufbx_vec2 points[4]; // ufbxi_uninit
  23216. uint32_t num_steps = 0;
  23217. while (indices_left > 3) {
  23218. points[0] = ufbxi_ngon_project(nc, point_indices[0]);
  23219. points[1] = ufbxi_ngon_project(nc, point_indices[1]);
  23220. points[2] = ufbxi_ngon_project(nc, point_indices[2]);
  23221. points[3] = ufbxi_ngon_project(nc, point_indices[3]);
  23222. weights[0] = ufbxi_ngon_tri_weight(points + 0);
  23223. weights[1] = ufbxi_ngon_tri_weight(points + 1);
  23224. uint32_t first_side = weights[1] > weights[0] ? 1 : 0;
  23225. bool clipped = false;
  23226. ufbxi_nounroll for (uint32_t side_ix = 0; side_ix < 2; side_ix++) {
  23227. uint32_t side = side_ix ^ first_side;
  23228. if (!(weights[side] >= 0.0f)) break;
  23229. // If there is no reflex angle contained within the triangle formed
  23230. // by `{ a, b, c }` connect the vertices `a - c` (prev, next) directly.
  23231. if (!ufbxi_kd_check(nc, points + side, point_indices + side)) {
  23232. uint32_t ia = point_indices[side + 0];
  23233. uint32_t ib = point_indices[side + 1];
  23234. uint32_t ic = point_indices[side + 2];
  23235. // Mark as clipped
  23236. edges[ib*2 + 0] |= 0x80000000;
  23237. edges[ib*2 + 1] |= 0x80000000;
  23238. edges[ic*2 + 0] = ia;
  23239. edges[ia*2 + 1] = ic;
  23240. indices_left -= 1;
  23241. // TODO: This may cause O(n^2) behavior!
  23242. num_steps = 0;
  23243. if (side == 1) {
  23244. point_indices[2] = point_indices[3];
  23245. point_indices[3] = edges[point_indices[3]*2 + 1];
  23246. } else {
  23247. point_indices[1] = point_indices[0];
  23248. point_indices[0] = edges[point_indices[0]*2 + 0];
  23249. }
  23250. clipped = true;
  23251. break;
  23252. }
  23253. }
  23254. if (clipped) continue;
  23255. // Continue forward
  23256. point_indices[0] = point_indices[1];
  23257. point_indices[1] = point_indices[2];
  23258. point_indices[2] = point_indices[3];
  23259. point_indices[3] = edges[point_indices[3]*2 + 1];
  23260. num_steps++;
  23261. // If we have walked around the entire polygon it is irregular and
  23262. // ear cutting won't find any more triangles.
  23263. // TODO: This could be stricter?
  23264. if (num_steps >= face.num_indices*2) break;
  23265. }
  23266. // Fallback: Cut non-ears until the polygon is completed.
  23267. // TODO: Could do something better here..
  23268. uint32_t ix = point_indices[1];
  23269. while (indices_left > 3) {
  23270. uint32_t prev = edges[ix*2 + 0];
  23271. uint32_t next = edges[ix*2 + 1];
  23272. // Mark as clipped
  23273. edges[ix*2 + 0] |= 0x80000000;
  23274. edges[ix*2 + 1] |= 0x80000000;
  23275. edges[prev*2 + 1] = next;
  23276. edges[next*2 + 0] = prev;
  23277. indices_left -= 1;
  23278. ix = next;
  23279. }
  23280. // Now we have a single triangle left at `ix`.
  23281. edges[ix*2 + 0] |= 0x80000000;
  23282. edges[ix*2 + 1] |= 0x80000000;
  23283. }
  23284. // Expand the adjacency information `edges` into proper triangles.
  23285. // Care needs to be taken here as both refer to the same memory area:
  23286. // The last 4 triangles may overlap in source and destination so we write
  23287. // them to a stack buffer and copy them over in the end.
  23288. uint32_t max_triangles = face.num_indices - 2;
  23289. uint32_t num_triangles = 0, num_last_triangles = 0;
  23290. uint32_t last_triangles[4*3]; // ufbxi_uninit
  23291. uint32_t index_begin = face.index_begin;
  23292. for (uint32_t ix = 0; ix < face.num_indices; ix++) {
  23293. uint32_t prev = edges[ix*2 + 0];
  23294. uint32_t next = edges[ix*2 + 1];
  23295. if (!(prev & 0x80000000)) continue;
  23296. uint32_t *dst = indices + num_triangles * 3;
  23297. if (num_triangles + 4 >= max_triangles) {
  23298. dst = last_triangles + num_last_triangles * 3;
  23299. num_last_triangles++;
  23300. }
  23301. dst[0] = index_begin + (prev & 0x7fffffff);
  23302. dst[1] = index_begin + ix;
  23303. dst[2] = index_begin + (next & 0x7fffffff);
  23304. num_triangles++;
  23305. }
  23306. // Copy over the last triangles
  23307. ufbx_assert(num_triangles == max_triangles);
  23308. memcpy(indices + (max_triangles - num_last_triangles) * 3, last_triangles, num_last_triangles * 3 * sizeof(uint32_t));
  23309. return num_triangles;
  23310. }
  23311. #endif
  23312. static int ufbxi_cmp_topo_index_prev_next(const void *va, const void *vb)
  23313. {
  23314. const ufbx_topo_edge *a = (const ufbx_topo_edge*)va, *b = (const ufbx_topo_edge*)vb;
  23315. if ((int32_t)a->prev != (int32_t)b->prev) return (int32_t)a->prev < (int32_t)b->prev ? -1 : +1;
  23316. if ((int32_t)a->next != (int32_t)b->next) return (int32_t)a->next < (int32_t)b->next ? -1 : +1;
  23317. return 0;
  23318. }
  23319. static int ufbxi_cmp_topo_index_index(const void *va, const void *vb)
  23320. {
  23321. const ufbx_topo_edge *a = (const ufbx_topo_edge*)va, *b = (const ufbx_topo_edge*)vb;
  23322. if ((int32_t)a->index != (int32_t)b->index) return (int32_t)a->index < (int32_t)b->index ? -1 : +1;
  23323. return 0;
  23324. }
  23325. ufbxi_noinline static void ufbxi_compute_topology(const ufbx_mesh *mesh, ufbx_topo_edge *topo)
  23326. {
  23327. size_t num_indices = mesh->num_indices;
  23328. // Temporarily use `prev` and `next` for vertices
  23329. for (uint32_t fi = 0; fi < mesh->num_faces; fi++) {
  23330. ufbx_face face = mesh->faces.data[fi];
  23331. for (uint32_t pi = 0; pi < face.num_indices; pi++) {
  23332. ufbx_topo_edge *te = &topo[face.index_begin + pi];
  23333. uint32_t ni = (pi + 1) % face.num_indices;
  23334. uint32_t va = mesh->vertex_indices.data[face.index_begin + pi];
  23335. uint32_t vb = mesh->vertex_indices.data[face.index_begin + ni];
  23336. if (vb < va) {
  23337. uint32_t vt = va; va = vb; vb = vt;
  23338. }
  23339. te->index = face.index_begin + pi;
  23340. te->twin = UFBX_NO_INDEX;
  23341. te->edge = UFBX_NO_INDEX;
  23342. te->prev = va;
  23343. te->next = vb;
  23344. te->face = fi;
  23345. te->flags = (ufbx_topo_flags)0;
  23346. }
  23347. }
  23348. // TODO: Macro unstable/non allocating sort
  23349. qsort(topo, num_indices, sizeof(ufbx_topo_edge), &ufbxi_cmp_topo_index_prev_next);
  23350. if (mesh->edges.data) {
  23351. for (uint32_t ei = 0; ei < mesh->num_edges; ei++) {
  23352. ufbx_edge edge = mesh->edges.data[ei];
  23353. uint32_t va = mesh->vertex_indices.data[edge.a];
  23354. uint32_t vb = mesh->vertex_indices.data[edge.b];
  23355. if (vb < va) {
  23356. uint32_t vt = va; va = vb; vb = vt;
  23357. }
  23358. size_t ix = num_indices;
  23359. ufbxi_macro_lower_bound_eq(ufbx_topo_edge, 32, &ix, topo, 0, num_indices,
  23360. (a->prev == va ? a->next < vb : a->prev < va), (a->prev == va && a->next == vb));
  23361. for (; ix < num_indices && topo[ix].prev == va && topo[ix].next == vb; ix++) {
  23362. topo[ix].edge = ei;
  23363. }
  23364. }
  23365. }
  23366. // Connect paired edges
  23367. for (size_t i0 = 0; i0 < num_indices; ) {
  23368. size_t i1 = i0;
  23369. uint32_t a = topo[i0].prev, b = topo[i0].next;
  23370. while (i1 + 1 < num_indices && topo[i1 + 1].prev == a && topo[i1 + 1].next == b) i1++;
  23371. if (i1 == i0 + 1) {
  23372. topo[i0].twin = topo[i1].index;
  23373. topo[i1].twin = topo[i0].index;
  23374. } else if (i1 > i0 + 1) {
  23375. for (size_t i = i0; i <= i1; i++) {
  23376. topo[i].flags = (ufbx_topo_flags)(topo[i].flags | UFBX_TOPO_NON_MANIFOLD);
  23377. }
  23378. }
  23379. i0 = i1 + 1;
  23380. }
  23381. // TODO: Macro unstable/non allocating sort
  23382. qsort(topo, num_indices, sizeof(ufbx_topo_edge), &ufbxi_cmp_topo_index_index);
  23383. // Fix `prev` and `next` to the actual index values
  23384. for (uint32_t fi = 0; fi < mesh->num_faces; fi++) {
  23385. ufbx_face face = mesh->faces.data[fi];
  23386. for (uint32_t i = 0; i < face.num_indices; i++) {
  23387. ufbx_topo_edge *to = &topo[face.index_begin + i];
  23388. to->prev = (uint32_t)(face.index_begin + (i + face.num_indices - 1) % face.num_indices);
  23389. to->next = (uint32_t)(face.index_begin + (i + 1) % face.num_indices);
  23390. }
  23391. }
  23392. }
  23393. static bool ufbxi_is_edge_smooth(const ufbx_mesh *mesh, const ufbx_topo_edge *topo, size_t num_topo, uint32_t index, bool assume_smooth)
  23394. {
  23395. ufbxi_ignore(num_topo);
  23396. ufbx_assert((size_t)index < num_topo);
  23397. if (mesh->edge_smoothing.data) {
  23398. uint32_t edge = topo[index].edge;
  23399. if (edge != UFBX_NO_INDEX && mesh->edge_smoothing.data[edge]) return true;
  23400. }
  23401. if (mesh->face_smoothing.data) {
  23402. if (mesh->face_smoothing.data[topo[index].face]) return true;
  23403. uint32_t twin = topo[index].twin;
  23404. if (twin != UFBX_NO_INDEX) {
  23405. if (mesh->face_smoothing.data[topo[twin].face]) return true;
  23406. }
  23407. }
  23408. if (!mesh->edge_smoothing.data && !mesh->face_smoothing.data && mesh->vertex_normal.exists) {
  23409. uint32_t twin = topo[index].twin;
  23410. if (twin != UFBX_NO_INDEX && mesh->vertex_normal.exists) {
  23411. ufbx_assert((size_t)twin < num_topo);
  23412. ufbx_vec3 a0 = ufbx_get_vertex_vec3(&mesh->vertex_normal, index);
  23413. ufbx_vec3 a1 = ufbx_get_vertex_vec3(&mesh->vertex_normal, topo[index].next);
  23414. ufbx_vec3 b0 = ufbx_get_vertex_vec3(&mesh->vertex_normal, topo[twin].next);
  23415. ufbx_vec3 b1 = ufbx_get_vertex_vec3(&mesh->vertex_normal, twin);
  23416. if (a0.x == b0.x && a0.y == b0.y && a0.z == b0.z) return true;
  23417. if (a1.x == b1.x && a1.y == b1.y && a1.z == b1.z) return true;
  23418. }
  23419. } else if (assume_smooth) {
  23420. return true;
  23421. }
  23422. return false;
  23423. }
  23424. // -- Subdivision
  23425. #if UFBXI_FEATURE_SUBDIVISION
  23426. typedef struct {
  23427. const void *data;
  23428. ufbx_real weight;
  23429. } ufbxi_subdivide_input;
  23430. typedef int ufbxi_subdivide_sum_fn(void *user, void *output, const ufbxi_subdivide_input *inputs, size_t num_inputs);
  23431. typedef struct {
  23432. ufbxi_subdivide_sum_fn *sum_fn;
  23433. void *sum_user;
  23434. const void *values;
  23435. size_t stride;
  23436. const uint32_t *indices;
  23437. bool check_split_data;
  23438. bool ignore_indices;
  23439. ufbx_subdivision_boundary boundary;
  23440. } ufbxi_subdivide_layer_input;
  23441. typedef struct {
  23442. void *values;
  23443. size_t num_values;
  23444. uint32_t *indices;
  23445. size_t num_indices;
  23446. bool unique_per_vertex;
  23447. } ufbxi_subdivide_layer_output;
  23448. typedef struct {
  23449. ufbx_subdivision_weight *weights;
  23450. size_t num_weights;
  23451. } ufbxi_subdivision_vertex_weights;
  23452. typedef struct {
  23453. ufbxi_mesh_imp *imp;
  23454. ufbx_error error;
  23455. ufbx_mesh *src_mesh_ptr;
  23456. ufbx_mesh src_mesh;
  23457. ufbx_mesh dst_mesh;
  23458. ufbx_topo_edge *topo;
  23459. size_t num_topo;
  23460. ufbx_subdivide_opts opts;
  23461. ufbxi_allocator ator_result;
  23462. ufbxi_allocator ator_tmp;
  23463. ufbxi_buf result;
  23464. ufbxi_buf tmp;
  23465. ufbxi_buf source;
  23466. ufbxi_subdivide_input *inputs;
  23467. size_t inputs_cap;
  23468. ufbx_real *tmp_vertex_weights;
  23469. ufbx_subdivision_weight *tmp_weights;
  23470. size_t total_weights;
  23471. size_t max_vertex_weights;
  23472. } ufbxi_subdivide_context;
  23473. static int ufbxi_subdivide_sum_vec2(void *user, void *output, const ufbxi_subdivide_input *inputs, size_t num_inputs)
  23474. {
  23475. (void)user;
  23476. ufbx_vec2 dst = { 0 };
  23477. ufbxi_nounroll for (size_t i = 0; i != num_inputs; i++) {
  23478. const ufbx_vec2 *src = (const ufbx_vec2*)inputs[i].data;
  23479. ufbx_real weight = inputs[i].weight;
  23480. dst.x += src->x * weight;
  23481. dst.y += src->y * weight;
  23482. }
  23483. *(ufbx_vec2*)output = dst;
  23484. return 1;
  23485. }
  23486. static int ufbxi_subdivide_sum_vec3(void *user, void *output, const ufbxi_subdivide_input *inputs, size_t num_inputs)
  23487. {
  23488. (void)user;
  23489. ufbx_vec3 dst = { 0 };
  23490. ufbxi_nounroll for (size_t i = 0; i != num_inputs; i++) {
  23491. const ufbx_vec3 *src = (const ufbx_vec3*)inputs[i].data;
  23492. ufbx_real weight = inputs[i].weight;
  23493. dst.x += src->x * weight;
  23494. dst.y += src->y * weight;
  23495. dst.z += src->z * weight;
  23496. }
  23497. *(ufbx_vec3*)output = dst;
  23498. return 1;
  23499. }
  23500. static int ufbxi_subdivide_sum_vec4(void *user, void *output, const ufbxi_subdivide_input *inputs, size_t num_inputs)
  23501. {
  23502. (void)user;
  23503. ufbx_vec4 dst = { 0 };
  23504. ufbxi_nounroll for (size_t i = 0; i != num_inputs; i++) {
  23505. const ufbx_vec4 *src = (const ufbx_vec4*)inputs[i].data;
  23506. ufbx_real weight = inputs[i].weight;
  23507. dst.x += src->x * weight;
  23508. dst.y += src->y * weight;
  23509. dst.z += src->z * weight;
  23510. dst.w += src->w * weight;
  23511. }
  23512. *(ufbx_vec4*)output = dst;
  23513. return 1;
  23514. }
  23515. static ufbxi_noinline int ufbxi_cmp_subdivision_weight(const void *va, const void *vb)
  23516. {
  23517. ufbx_subdivision_weight a = *(const ufbx_subdivision_weight*)va, b = *(const ufbx_subdivision_weight*)vb;
  23518. ufbxi_dev_assert(a.index != b.index);
  23519. if (a.weight != b.weight) return a.weight > b.weight ? -1 : +1;
  23520. return a.index < b.index ? -1 : +1;
  23521. }
  23522. static int ufbxi_subdivide_sum_vertex_weights(void *user, void *output, const ufbxi_subdivide_input *inputs, size_t num_inputs)
  23523. {
  23524. ufbxi_subdivide_context *sc = (ufbxi_subdivide_context*)user;
  23525. ufbx_real *vertex_weights = sc->tmp_vertex_weights;
  23526. ufbx_subdivision_weight *tmp_weights = sc->tmp_weights;
  23527. size_t num_weights = 0;
  23528. ufbxi_nounroll for (size_t input_ix = 0; input_ix != num_inputs; input_ix++) {
  23529. ufbxi_subdivision_vertex_weights src = *(const ufbxi_subdivision_vertex_weights*)inputs[input_ix].data;
  23530. ufbx_real input_weight = inputs[input_ix].weight;
  23531. for (size_t weight_ix = 0; weight_ix < src.num_weights; weight_ix++) {
  23532. ufbx_real weight = input_weight * src.weights[weight_ix].weight;
  23533. if (weight < 1.175494351e-38f) continue;
  23534. uint32_t vx = src.weights[weight_ix].index;
  23535. ufbxi_dev_assert(vx < sc->src_mesh.num_vertices);
  23536. ufbx_real prev = vertex_weights[vx];
  23537. vertex_weights[vx] = prev + weight;
  23538. if (prev == 0.0f) {
  23539. tmp_weights[num_weights++].index = vx;
  23540. }
  23541. }
  23542. }
  23543. ufbxi_nounroll for (size_t i = 0; i != num_weights; i++) {
  23544. uint32_t vx = tmp_weights[i].index;
  23545. tmp_weights[i].weight = vertex_weights[vx];
  23546. vertex_weights[vx] = 0.0f;
  23547. }
  23548. qsort(tmp_weights, num_weights, sizeof(ufbx_subdivision_weight), ufbxi_cmp_subdivision_weight);
  23549. if (sc->max_vertex_weights != SIZE_MAX) {
  23550. num_weights = ufbxi_min_sz(sc->max_vertex_weights, num_weights);
  23551. // Normalize weights
  23552. ufbx_real prefix_weight = 0.0f;
  23553. ufbxi_nounroll for (size_t i = 0; i != num_weights; i++) {
  23554. prefix_weight += tmp_weights[i].weight;
  23555. }
  23556. ufbxi_nounroll for (size_t i = 0; i != num_weights; i++) {
  23557. tmp_weights[i].weight /= prefix_weight;
  23558. }
  23559. }
  23560. sc->total_weights += num_weights;
  23561. ufbx_subdivision_weight *weights = ufbxi_push_copy(&sc->tmp, ufbx_subdivision_weight, num_weights, tmp_weights);
  23562. ufbxi_check_err(&sc->error, weights);
  23563. ufbxi_subdivision_vertex_weights *dst = (ufbxi_subdivision_vertex_weights*)output;
  23564. dst->weights = weights;
  23565. dst->num_weights = num_weights;
  23566. return 1;
  23567. }
  23568. static ufbxi_subdivide_sum_fn *const ufbxi_real_sum_fns[] = {
  23569. NULL,
  23570. &ufbxi_subdivide_sum_vec2,
  23571. &ufbxi_subdivide_sum_vec3,
  23572. &ufbxi_subdivide_sum_vec4,
  23573. };
  23574. ufbxi_noinline static bool ufbxi_is_edge_split(const ufbxi_subdivide_layer_input *input, const ufbx_topo_edge *topo, uint32_t index)
  23575. {
  23576. uint32_t twin = topo[index].twin;
  23577. if (twin != UFBX_NO_INDEX) {
  23578. uint32_t a0 = input->indices[index];
  23579. uint32_t a1 = input->indices[topo[index].next];
  23580. uint32_t b0 = input->indices[topo[twin].next];
  23581. uint32_t b1 = input->indices[twin];
  23582. if (a0 == b0 && a1 == b1) return false;
  23583. if (!input->check_split_data) return true;
  23584. size_t stride = input->stride;
  23585. char *da0 = (char*)input->values + a0 * stride;
  23586. char *da1 = (char*)input->values + a1 * stride;
  23587. char *db0 = (char*)input->values + b0 * stride;
  23588. char *db1 = (char*)input->values + b1 * stride;
  23589. if (!memcmp(da0, db0, stride) && !memcmp(da1, db1, stride)) return false;
  23590. return true;
  23591. }
  23592. return false;
  23593. }
  23594. static ufbx_real ufbxi_edge_crease(const ufbx_mesh *mesh, bool split, const ufbx_topo_edge *topo, uint32_t index)
  23595. {
  23596. if (topo[index].twin == UFBX_NO_INDEX) return 1.0f;
  23597. if (split) return 1.0f;
  23598. if (mesh->edge_crease.data && topo[index].edge != UFBX_NO_INDEX) return mesh->edge_crease.data[topo[index].edge] * (ufbx_real)10.0;
  23599. return 0.0f;
  23600. }
  23601. static ufbxi_noinline int ufbxi_subdivide_layer(ufbxi_subdivide_context *sc, ufbxi_subdivide_layer_output *output, const ufbxi_subdivide_layer_input *input)
  23602. {
  23603. ufbx_subdivision_boundary boundary = input->boundary;
  23604. const ufbx_mesh *mesh = &sc->src_mesh;
  23605. const ufbx_topo_edge *topo = sc->topo;
  23606. size_t num_topo = sc->num_topo;
  23607. uint32_t *edge_indices = ufbxi_push(&sc->result, uint32_t, mesh->num_indices);
  23608. ufbxi_check_err(&sc->error, edge_indices);
  23609. size_t num_edge_values = 0;
  23610. for (uint32_t ix = 0; ix < (uint32_t)mesh->num_indices; ix++) {
  23611. uint32_t twin = topo[ix].twin;
  23612. if (twin < ix && !ufbxi_is_edge_split(input, topo, ix)) {
  23613. edge_indices[ix] = edge_indices[twin];
  23614. } else {
  23615. edge_indices[ix] = (uint32_t)num_edge_values++;
  23616. }
  23617. }
  23618. size_t stride = input->stride;
  23619. size_t num_initial_values = (num_edge_values + mesh->num_faces + mesh->num_indices);
  23620. char *values = (char*)ufbxi_push_size(&sc->tmp, stride, num_initial_values);
  23621. ufbxi_check_err(&sc->error, values);
  23622. char *face_values = values;
  23623. char *edge_values = face_values + mesh->num_faces * stride;
  23624. char *vertex_values = edge_values + num_edge_values * stride;
  23625. size_t num_vertex_values = 0;
  23626. uint32_t *vertex_indices = ufbxi_push(&sc->result, uint32_t, mesh->num_indices);
  23627. ufbxi_check_err(&sc->error, vertex_indices);
  23628. size_t min_inputs = ufbxi_max_sz(32, mesh->max_face_triangles + 2);
  23629. ufbxi_check_err(&sc->error, ufbxi_grow_array(&sc->ator_tmp, &sc->inputs, &sc->inputs_cap, min_inputs));
  23630. ufbxi_subdivide_input *inputs = sc->inputs;
  23631. // Assume initially unique per vertex, remove if not the case
  23632. output->unique_per_vertex = true;
  23633. bool sharp_corners = false;
  23634. bool sharp_splits = false;
  23635. bool sharp_all = false;
  23636. switch (boundary) {
  23637. case UFBX_SUBDIVISION_BOUNDARY_DEFAULT:
  23638. case UFBX_SUBDIVISION_BOUNDARY_SHARP_NONE:
  23639. case UFBX_SUBDIVISION_BOUNDARY_LEGACY:
  23640. // All smooth
  23641. break;
  23642. case UFBX_SUBDIVISION_BOUNDARY_SHARP_CORNERS:
  23643. sharp_corners = true;
  23644. break;
  23645. case UFBX_SUBDIVISION_BOUNDARY_SHARP_BOUNDARY:
  23646. sharp_corners = true;
  23647. sharp_splits = true;
  23648. break;
  23649. case UFBX_SUBDIVISION_BOUNDARY_SHARP_INTERIOR:
  23650. sharp_all = true;
  23651. break;
  23652. default:
  23653. ufbxi_unreachable("Bad boundary mode");
  23654. }
  23655. ufbxi_subdivide_sum_fn *sum_fn = input->sum_fn;
  23656. void *sum_user = input->sum_user;
  23657. // Mark unused indices as `UFBX_NO_INDEX` so we can patch non-manifold
  23658. ufbxi_nounroll for (size_t i = 0; i < mesh->num_indices; i++) {
  23659. vertex_indices[i] = UFBX_NO_INDEX;
  23660. }
  23661. // Face points
  23662. for (size_t fi = 0; fi < mesh->num_faces; fi++) {
  23663. ufbx_face face = mesh->faces.data[fi];
  23664. char *dst = face_values + fi * stride;
  23665. ufbx_real weight = 1.0f / (ufbx_real)face.num_indices;
  23666. for (uint32_t ci = 0; ci < face.num_indices; ci++) {
  23667. uint32_t ix = face.index_begin + ci;
  23668. inputs[ci].data = (const char*)input->values + input->indices[ix] * stride;
  23669. inputs[ci].weight = weight;
  23670. }
  23671. ufbxi_check_err(&sc->error, sum_fn(sum_user, dst, inputs, face.num_indices));
  23672. }
  23673. // Edge points
  23674. for (uint32_t ix = 0; ix < mesh->num_indices; ix++) {
  23675. char *dst = edge_values + edge_indices[ix] * stride;
  23676. uint32_t twin = topo[ix].twin;
  23677. bool split = ufbxi_is_edge_split(input, topo, ix);
  23678. if (split || (topo[ix].flags & UFBX_TOPO_NON_MANIFOLD) != 0) {
  23679. output->unique_per_vertex = false;
  23680. }
  23681. ufbx_real crease = 0.0f;
  23682. if (split || twin == UFBX_NO_INDEX) {
  23683. crease = 1.0f;
  23684. } else if (topo[ix].edge != UFBX_NO_INDEX && mesh->edge_crease.data) {
  23685. crease = mesh->edge_crease.data[topo[ix].edge] * (ufbx_real)10.0;
  23686. }
  23687. if (sharp_all) crease = 1.0f;
  23688. const char *v0 = (const char*)input->values + input->indices[ix] * stride;
  23689. const char *v1 = (const char*)input->values + input->indices[topo[ix].next] * stride;
  23690. // TODO: Unify
  23691. if (twin < ix && !split) {
  23692. // Already calculated
  23693. } else if (crease <= 0.0f) {
  23694. const char *f0 = face_values + topo[ix].face * stride;
  23695. const char *f1 = face_values + topo[twin].face * stride;
  23696. inputs[0].data = v0;
  23697. inputs[0].weight = 0.25f;
  23698. inputs[1].data = v1;
  23699. inputs[1].weight = 0.25f;
  23700. inputs[2].data = f0;
  23701. inputs[2].weight = 0.25f;
  23702. inputs[3].data = f1;
  23703. inputs[3].weight = 0.25f;
  23704. ufbxi_check_err(&sc->error, sum_fn(sum_user, dst, inputs, 4));
  23705. } else if (crease >= 1.0f) {
  23706. inputs[0].data = v0;
  23707. inputs[0].weight = 0.5f;
  23708. inputs[1].data = v1;
  23709. inputs[1].weight = 0.5f;
  23710. ufbxi_check_err(&sc->error, sum_fn(sum_user, dst, inputs, 2));
  23711. } else if (crease < 1.0f) {
  23712. const char *f0 = face_values + topo[ix].face * stride;
  23713. const char *f1 = face_values + topo[twin].face * stride;
  23714. ufbx_real w0 = 0.25f + 0.25f * crease;
  23715. ufbx_real w1 = 0.25f - 0.25f * crease;
  23716. inputs[0].data = v0;
  23717. inputs[0].weight = w0;
  23718. inputs[1].data = v1;
  23719. inputs[1].weight = w0;
  23720. inputs[2].data = f0;
  23721. inputs[2].weight = w1;
  23722. inputs[3].data = f1;
  23723. inputs[3].weight = w1;
  23724. ufbxi_check_err(&sc->error, sum_fn(sum_user, dst, inputs, 4));
  23725. }
  23726. }
  23727. // Vertex points
  23728. for (size_t vi = 0; vi < mesh->num_vertices; vi++) {
  23729. uint32_t original_start = mesh->vertex_first_index.data[vi];
  23730. if (original_start == UFBX_NO_INDEX) continue;
  23731. // Find a topological boundary, or if not found a split edge
  23732. uint32_t start = original_start;
  23733. for (uint32_t cur = start;;) {
  23734. uint32_t prev = ufbx_topo_prev_vertex_edge(topo, num_topo, cur);
  23735. if (prev == UFBX_NO_INDEX) { start = cur; break; } // Topological boundary: Stop and use as start
  23736. if (ufbxi_is_edge_split(input, topo, prev)) start = cur; // Split edge: Consider as start
  23737. if (prev == original_start) break; // Loop: Stop, use original start or split if found
  23738. cur = prev;
  23739. }
  23740. original_start = start;
  23741. while (start != UFBX_NO_INDEX) {
  23742. if (start != original_start) {
  23743. output->unique_per_vertex = false;
  23744. }
  23745. uint32_t value_index = (uint32_t)num_vertex_values++;
  23746. char *dst = vertex_values + value_index * stride;
  23747. // We need to compute the average crease value and keep track of
  23748. // two creased edges, if there's more we use the corner rule that
  23749. // does not need the information.
  23750. ufbx_real total_crease = 0.0f;
  23751. size_t num_crease = 0;
  23752. size_t num_split = 0;
  23753. bool on_boundary = false;
  23754. bool non_manifold = false;
  23755. size_t crease_input_indices[2]; // ufbxi_uninit
  23756. // At start we always have two edges and a single face
  23757. uint32_t start_prev = topo[start].prev;
  23758. uint32_t end_edge = topo[start_prev].twin;
  23759. size_t valence = 2;
  23760. non_manifold |= (topo[start].flags & UFBX_TOPO_NON_MANIFOLD) != 0;
  23761. non_manifold |= (topo[start_prev].flags & UFBX_TOPO_NON_MANIFOLD) != 0;
  23762. const char *v0 = (const char*)input->values + input->indices[start] * stride;
  23763. size_t num_inputs = 4;
  23764. {
  23765. const char *e0 = (const char*)input->values + input->indices[topo[start].next] * stride;
  23766. const char *e1 = (const char*)input->values + input->indices[start_prev] * stride;
  23767. const char *f0 = face_values + topo[start].face * stride;
  23768. inputs[0].data = v0;
  23769. inputs[1].data = e0;
  23770. inputs[2].data = e1;
  23771. inputs[3].data = f0;
  23772. }
  23773. bool start_split = ufbxi_is_edge_split(input, topo, start);
  23774. bool prev_split = end_edge != UFBX_NO_INDEX && ufbxi_is_edge_split(input, topo, end_edge);
  23775. // Either of the first two edges may be creased
  23776. ufbx_real start_crease = ufbxi_edge_crease(mesh, start_split, topo, start);
  23777. if (start_crease > 0.0f) {
  23778. total_crease += start_crease;
  23779. crease_input_indices[num_crease++] = 1;
  23780. }
  23781. ufbx_real prev_crease = ufbxi_edge_crease(mesh, prev_split, topo, start_prev);
  23782. if (prev_crease > 0.0f) {
  23783. total_crease += prev_crease;
  23784. crease_input_indices[num_crease++] = 2;
  23785. }
  23786. if (end_edge != UFBX_NO_INDEX) {
  23787. if (prev_split) {
  23788. num_split++;
  23789. }
  23790. } else {
  23791. on_boundary = true;
  23792. }
  23793. ufbxi_check_err(&sc->error, vertex_indices[start] == UFBX_NO_INDEX);
  23794. vertex_indices[start] = value_index;
  23795. if (start_split) {
  23796. // We need to special case if the first edge is split as we have
  23797. // handled it already in the code above..
  23798. start = ufbx_topo_next_vertex_edge(topo, num_topo, start);
  23799. num_split++;
  23800. } else {
  23801. // Follow vertex edges until we either hit a topological/split boundary
  23802. // or loop back to the left edge we accounted for in `start_prev`
  23803. uint32_t cur = start;
  23804. for (;;) {
  23805. cur = ufbx_topo_next_vertex_edge(topo, num_topo, cur);
  23806. // Topological boundary: Finished
  23807. if (cur == UFBX_NO_INDEX) {
  23808. on_boundary = true;
  23809. start = UFBX_NO_INDEX;
  23810. break;
  23811. }
  23812. non_manifold |= (topo[cur].flags & UFBX_TOPO_NON_MANIFOLD) != 0;
  23813. ufbxi_check_err(&sc->error, vertex_indices[cur] == UFBX_NO_INDEX);
  23814. vertex_indices[cur] = value_index;
  23815. bool split = ufbxi_is_edge_split(input, topo, cur);
  23816. // Looped: Add the face from the other side still if not split
  23817. if (cur == end_edge && !split) {
  23818. ufbxi_check_err(&sc->error, ufbxi_grow_array(&sc->ator_tmp, &sc->inputs, &sc->inputs_cap, num_inputs + 1));
  23819. const char *f0 = face_values + topo[cur].face * stride;
  23820. inputs[num_inputs].data = f0;
  23821. start = UFBX_NO_INDEX;
  23822. num_inputs += 1;
  23823. break;
  23824. }
  23825. // Add the edge crease, this also handles boundaries as they
  23826. // have an implicit crease of 1.0 using `ufbxi_edge_crease()`
  23827. ufbx_real cur_crease = ufbxi_edge_crease(mesh, split, topo, cur);
  23828. if (cur_crease > 0.0f) {
  23829. total_crease += cur_crease;
  23830. if (num_crease < 2) crease_input_indices[num_crease] = num_inputs;
  23831. num_crease++;
  23832. }
  23833. // Add the new edge and face to the sum
  23834. {
  23835. ufbxi_check_err(&sc->error, ufbxi_grow_array(&sc->ator_tmp, &sc->inputs, &sc->inputs_cap, num_inputs + 2));
  23836. inputs = sc->inputs;
  23837. const char *e0 = (char*)input->values + input->indices[topo[cur].next] * stride;
  23838. const char *f0 = face_values + topo[cur].face * stride;
  23839. inputs[num_inputs + 0].data = e0;
  23840. inputs[num_inputs + 1].data = f0;
  23841. num_inputs += 2;
  23842. }
  23843. valence++;
  23844. // If we landed at a split edge advance to the next one
  23845. // and continue from there in the outer loop
  23846. if (split) {
  23847. start = ufbx_topo_next_vertex_edge(topo, num_topo, cur);
  23848. num_split++;
  23849. break;
  23850. }
  23851. }
  23852. }
  23853. if (start == original_start) start = UFBX_NO_INDEX;
  23854. // Weights for various subdivision masks
  23855. ufbx_real fe_weight = 1.0f / (ufbx_real)(valence*valence);
  23856. ufbx_real v_weight = (ufbx_real)(valence - 2) / (ufbx_real)valence;
  23857. // Select the right subdivision mask depending on valence and crease
  23858. if (num_crease > 2
  23859. || (sharp_corners && valence == 2 && (num_split > 0 || on_boundary))
  23860. || (sharp_splits && (num_split > 0 || on_boundary))
  23861. || sharp_all
  23862. || non_manifold) {
  23863. // Corner: Copy as-is
  23864. inputs[0].data = v0;
  23865. inputs[0].weight = 1.0f;
  23866. num_inputs = 1;
  23867. } else if (num_crease == 2) {
  23868. // Boundary: Interpolate edge
  23869. total_crease *= 0.5f;
  23870. if (total_crease < 0.0f) total_crease = 0.0f;
  23871. if (total_crease > 1.0f) total_crease = 1.0f;
  23872. inputs[0].weight = v_weight * (1.0f - total_crease) + 0.75f * total_crease;
  23873. ufbx_real few = fe_weight * (1.0f - total_crease);
  23874. for (size_t i = 1; i < num_inputs; i++) {
  23875. inputs[i].weight = few;
  23876. }
  23877. // Add weight to the creased edges
  23878. inputs[crease_input_indices[0]].weight += 0.125f * total_crease;
  23879. inputs[crease_input_indices[1]].weight += 0.125f * total_crease;
  23880. } else {
  23881. // Regular: Weighted sum with the accumulated edge/face points
  23882. inputs[0].weight = v_weight;
  23883. for (size_t i = 1; i < num_inputs; i++) {
  23884. inputs[i].weight = fe_weight;
  23885. }
  23886. }
  23887. if (mesh->vertex_crease.exists) {
  23888. ufbx_real v = ufbx_get_vertex_real(&mesh->vertex_crease, original_start);
  23889. v *= (ufbx_real)10.0;
  23890. if (v > 0.0f) {
  23891. if (v > 1.0) v = 1.0f;
  23892. ufbx_real iv = 1.0f - v;
  23893. inputs[0].weight = 1.0f * v + (inputs[0].weight) * iv;
  23894. for (size_t i = 1; i < num_inputs; i++) {
  23895. inputs[i].weight *= iv;
  23896. }
  23897. }
  23898. }
  23899. #if defined(UFBX_REGRESSION)
  23900. {
  23901. ufbx_real total_weight = 0.0f;
  23902. for (size_t i = 0; i < num_inputs; i++) {
  23903. total_weight += inputs[i].weight;
  23904. }
  23905. ufbx_assert(ufbx_fabs(total_weight - 1.0f) < 0.001f);
  23906. }
  23907. #endif
  23908. ufbxi_check_err(&sc->error, sum_fn(sum_user, dst, inputs, num_inputs));
  23909. }
  23910. }
  23911. // Copy non-manifold vertex values as-is
  23912. for (size_t old_ix = 0; old_ix < mesh->num_indices; old_ix++) {
  23913. uint32_t ix = vertex_indices[old_ix];
  23914. if (ix == UFBX_NO_INDEX) {
  23915. ix = (uint32_t)num_vertex_values++;
  23916. vertex_indices[old_ix] = ix;
  23917. const char *src = (const char*)input->values + input->indices[old_ix] * stride;
  23918. char *dst = vertex_values + ix * stride;
  23919. inputs[0].data = src;
  23920. inputs[0].weight = 1.0f;
  23921. ufbxi_check_err(&sc->error, sum_fn(sum_user, dst, inputs, 1));
  23922. }
  23923. }
  23924. ufbx_assert(num_vertex_values <= mesh->num_indices);
  23925. size_t num_values = num_edge_values + mesh->num_faces + num_vertex_values;
  23926. char *new_values = (char*)ufbxi_push_size(&sc->result, stride, (num_values+1));
  23927. ufbxi_check_err(&sc->error, new_values);
  23928. memset(new_values, 0, stride);
  23929. new_values += stride;
  23930. memcpy(new_values, values, num_values * stride);
  23931. output->values = new_values;
  23932. output->num_values = num_values;
  23933. if (!input->ignore_indices) {
  23934. uint32_t *new_indices = ufbxi_push(&sc->result, uint32_t, mesh->num_indices * 4);
  23935. ufbxi_check_err(&sc->error, new_indices);
  23936. uint32_t face_start = 0;
  23937. uint32_t edge_start = (uint32_t)(face_start + mesh->num_faces);
  23938. uint32_t vert_start = (uint32_t)(edge_start + num_edge_values);
  23939. uint32_t *p_ix = new_indices;
  23940. for (size_t ix = 0; ix < mesh->num_indices; ix++) {
  23941. p_ix[0] = vert_start + vertex_indices[ix];
  23942. p_ix[1] = edge_start + edge_indices[ix];
  23943. p_ix[2] = face_start + topo[ix].face;
  23944. p_ix[3] = edge_start + edge_indices[topo[ix].prev];
  23945. p_ix += 4;
  23946. }
  23947. output->indices = new_indices;
  23948. output->num_indices = mesh->num_indices * 4;
  23949. } else {
  23950. output->indices = NULL;
  23951. output->num_indices = 0;
  23952. }
  23953. return 1;
  23954. }
  23955. static ufbxi_noinline int ufbxi_subdivide_attrib(ufbxi_subdivide_context *sc, ufbx_vertex_attrib *attrib, ufbx_subdivision_boundary boundary, bool check_split_data)
  23956. {
  23957. if (!attrib->exists) return 1;
  23958. ufbx_assert(attrib->value_reals >= 2 && attrib->value_reals <= 4);
  23959. ufbxi_subdivide_layer_input input; // ufbxi_uninit
  23960. input.sum_fn = ufbxi_real_sum_fns[attrib->value_reals - 1];
  23961. input.sum_user = NULL;
  23962. input.values = attrib->values.data;
  23963. input.indices = attrib->indices.data;
  23964. input.stride = attrib->value_reals * sizeof(ufbx_real);
  23965. input.boundary = boundary;
  23966. input.check_split_data = check_split_data;
  23967. input.ignore_indices = false;
  23968. ufbxi_subdivide_layer_output output; // ufbxi_uninit
  23969. ufbxi_check_err(&sc->error, ufbxi_subdivide_layer(sc, &output, &input));
  23970. attrib->values.data = output.values;
  23971. attrib->indices.data = output.indices;
  23972. attrib->values.count = output.num_values;
  23973. attrib->indices.count = output.num_indices;
  23974. return 1;
  23975. }
  23976. static ufbxi_noinline ufbxi_subdivision_vertex_weights *ufbxi_subdivision_copy_weights(ufbxi_subdivide_context *sc, ufbx_subdivision_weight_range_list ranges, ufbx_subdivision_weight_list weights)
  23977. {
  23978. ufbxi_subdivision_vertex_weights *dst = ufbxi_push(&sc->tmp, ufbxi_subdivision_vertex_weights, ranges.count);
  23979. ufbxi_check_return_err(&sc->error, dst, NULL);
  23980. ufbxi_nounroll for (size_t i = 0; i != ranges.count; i++) {
  23981. ufbx_subdivision_weight_range range = ranges.data[i];
  23982. dst[i].weights = weights.data + range.weight_begin;
  23983. dst[i].num_weights = range.num_weights;
  23984. }
  23985. return dst;
  23986. }
  23987. static ufbxi_noinline ufbxi_subdivision_vertex_weights *ufbxi_init_source_vertex_weights(ufbxi_subdivide_context *sc, size_t num_vertices)
  23988. {
  23989. ufbxi_subdivision_vertex_weights *dst = ufbxi_push(&sc->tmp, ufbxi_subdivision_vertex_weights, num_vertices);
  23990. ufbx_subdivision_weight *weights = ufbxi_push(&sc->tmp, ufbx_subdivision_weight, num_vertices);
  23991. ufbxi_check_return_err(&sc->error, dst && weights, NULL);
  23992. ufbxi_nounroll for (size_t i = 0; i != num_vertices; i++) {
  23993. dst[i].weights = weights + i;
  23994. dst[i].num_weights = 1;
  23995. weights[i].index = (uint32_t)i;
  23996. weights[i].weight = 1.0f;
  23997. }
  23998. return dst;
  23999. }
  24000. static ufbxi_noinline ufbxi_subdivision_vertex_weights *ufbxi_init_skin_weights(ufbxi_subdivide_context *sc, size_t num_vertices, const ufbx_skin_deformer *skin)
  24001. {
  24002. ufbxi_subdivision_vertex_weights *dst = ufbxi_push(&sc->tmp, ufbxi_subdivision_vertex_weights, num_vertices);
  24003. ufbxi_check_return_err(&sc->error, dst, NULL);
  24004. for (size_t i = 0; i < num_vertices; i++) {
  24005. ufbxi_dev_assert(i < skin->vertices.count);
  24006. ufbx_skin_vertex vertex = skin->vertices.data[i];
  24007. size_t num_weights = ufbxi_min_sz(sc->max_vertex_weights, vertex.num_weights);
  24008. ufbx_subdivision_weight *weights = ufbxi_push(&sc->tmp, ufbx_subdivision_weight, num_weights);
  24009. ufbxi_check_err(&sc->error, weights);
  24010. const ufbx_skin_weight *skin_weights = skin->weights.data + vertex.weight_begin;
  24011. dst[i].weights = weights;
  24012. dst[i].num_weights = num_weights;
  24013. ufbxi_nounroll for (size_t wi = 0; wi != num_weights; wi++) {
  24014. ufbxi_check_err(&sc->error, skin_weights[wi].cluster_index <= INT32_MAX);
  24015. weights[wi].index = skin_weights[wi].cluster_index;
  24016. weights[wi].weight = skin_weights[wi].weight;
  24017. }
  24018. }
  24019. return dst;
  24020. }
  24021. static ufbxi_noinline int ufbxi_subdivide_weights(ufbxi_subdivide_context *sc, ufbx_subdivision_weight_range_list *ranges,
  24022. ufbx_subdivision_weight_list *weights, const ufbxi_subdivision_vertex_weights *src)
  24023. {
  24024. ufbxi_check_err(&sc->error, src);
  24025. ufbxi_subdivide_layer_input input; // ufbxi_uninit
  24026. input.sum_fn = ufbxi_subdivide_sum_vertex_weights;
  24027. input.sum_user = sc;
  24028. input.values = src;
  24029. input.indices = sc->src_mesh.vertex_indices.data;
  24030. input.stride = sizeof(ufbxi_subdivision_vertex_weights);
  24031. input.boundary = sc->opts.boundary;
  24032. input.check_split_data = false;
  24033. input.ignore_indices = true;
  24034. sc->total_weights = 0;
  24035. ufbxi_subdivide_layer_output output; // ufbxi_uninit
  24036. ufbxi_check_err(&sc->error, ufbxi_subdivide_layer(sc, &output, &input));
  24037. size_t num_vertices = output.num_values;
  24038. ufbx_assert(num_vertices == sc->dst_mesh.vertex_position.values.count);
  24039. ufbx_subdivision_weight_range *dst_ranges = ufbxi_push(&sc->result, ufbx_subdivision_weight_range, num_vertices);
  24040. ufbx_subdivision_weight *dst_weights = ufbxi_push(&sc->result, ufbx_subdivision_weight, sc->total_weights);
  24041. ufbxi_check_err(&sc->error, ranges && weights);
  24042. ufbxi_subdivision_vertex_weights *src_weights = (ufbxi_subdivision_vertex_weights*)output.values;
  24043. size_t weight_offset = 0;
  24044. for (size_t vi = 0; vi < num_vertices; vi++) {
  24045. ufbxi_subdivision_vertex_weights ws = src_weights[vi];
  24046. ufbxi_check_err(&sc->error, (size_t)UINT32_MAX - weight_offset >= ws.num_weights);
  24047. dst_ranges[vi].weight_begin = (uint32_t)weight_offset;
  24048. dst_ranges[vi].num_weights = (uint32_t)ws.num_weights;
  24049. memcpy(dst_weights + weight_offset, ws.weights, ws.num_weights * sizeof(ufbx_subdivision_weight));
  24050. weight_offset += ws.num_weights;
  24051. }
  24052. ranges->data = dst_ranges;
  24053. ranges->count = num_vertices;
  24054. weights->data = dst_weights;
  24055. weights->count = sc->total_weights;
  24056. return 1;
  24057. }
  24058. ufbxi_nodiscard static ufbxi_noinline int ufbxi_subdivide_vertex_crease(ufbxi_subdivide_context *sc, ufbx_vertex_real *ufbxi_restrict dst, const ufbx_vertex_real *ufbxi_restrict src)
  24059. {
  24060. size_t src_indices = src->indices.count;
  24061. size_t src_values = src->values.count;
  24062. dst->values.count = src_values + 1;
  24063. dst->values.data = ufbxi_push(&sc->result, ufbx_real, dst->values.count);
  24064. ufbxi_check_err(&sc->error, dst->values.data);
  24065. dst->values.data[src_values] = 0.0f;
  24066. dst->indices.count = src_indices * 4;
  24067. dst->indices.data = ufbxi_push(&sc->result, uint32_t, dst->indices.count);
  24068. ufbxi_check_err(&sc->error, dst->indices.data);
  24069. // Reduce the amount of vertex crease on each iteration
  24070. ufbxi_nounroll for (size_t i = 0; i < src_values; i++) {
  24071. ufbx_real crease = src->values.data[i];
  24072. if (crease < 0.999f) crease -= 0.1f;
  24073. if (crease < 0.0f) crease = 0.0f;
  24074. dst->values.data[i] = crease;
  24075. }
  24076. // Write the crease at the vertex corner and zero (at `src_values`) on other ones
  24077. uint32_t zero_index = (uint32_t)src_values;
  24078. ufbxi_nounroll for (size_t i = 0; i < src_indices; i++) {
  24079. uint32_t *quad = dst->indices.data + i * 4;
  24080. quad[0] = src->indices.data[i];
  24081. quad[1] = zero_index;
  24082. quad[2] = zero_index;
  24083. quad[3] = zero_index;
  24084. }
  24085. return 1;
  24086. }
  24087. ufbxi_nodiscard static ufbxi_noinline int ufbxi_subdivide_mesh_level(ufbxi_subdivide_context *sc)
  24088. {
  24089. const ufbx_mesh *mesh = &sc->src_mesh;
  24090. ufbx_mesh *result = &sc->dst_mesh;
  24091. *result = *mesh;
  24092. ufbx_topo_edge *topo = ufbxi_push(&sc->tmp, ufbx_topo_edge, mesh->num_indices);
  24093. ufbxi_check_err(&sc->error, topo);
  24094. ufbx_compute_topology(mesh, topo, mesh->num_indices);
  24095. sc->topo = topo;
  24096. sc->num_topo = mesh->num_indices;
  24097. ufbxi_check_err(&sc->error, ufbxi_subdivide_attrib(sc, (ufbx_vertex_attrib*)&result->vertex_position, sc->opts.boundary, false));
  24098. memset(&result->vertex_uv, 0, sizeof(result->vertex_uv));
  24099. memset(&result->vertex_tangent, 0, sizeof(result->vertex_tangent));
  24100. memset(&result->vertex_bitangent, 0, sizeof(result->vertex_bitangent));
  24101. memset(&result->vertex_color, 0, sizeof(result->vertex_color));
  24102. result->uv_sets.data = ufbxi_push_copy(&sc->result, ufbx_uv_set, result->uv_sets.count, result->uv_sets.data);
  24103. ufbxi_check_err(&sc->error, result->uv_sets.data);
  24104. result->color_sets.data = ufbxi_push_copy(&sc->result, ufbx_color_set, result->color_sets.count, result->color_sets.data);
  24105. ufbxi_check_err(&sc->error, result->color_sets.data);
  24106. ufbxi_for_list(ufbx_uv_set, set, result->uv_sets) {
  24107. ufbxi_check_err(&sc->error, ufbxi_subdivide_attrib(sc, (ufbx_vertex_attrib*)&set->vertex_uv, sc->opts.uv_boundary, true));
  24108. if (sc->opts.interpolate_tangents) {
  24109. ufbxi_check_err(&sc->error, ufbxi_subdivide_attrib(sc, (ufbx_vertex_attrib*)&set->vertex_tangent, sc->opts.uv_boundary, true));
  24110. ufbxi_check_err(&sc->error, ufbxi_subdivide_attrib(sc, (ufbx_vertex_attrib*)&set->vertex_bitangent, sc->opts.uv_boundary, true));
  24111. } else {
  24112. memset(&set->vertex_tangent, 0, sizeof(set->vertex_tangent));
  24113. memset(&set->vertex_bitangent, 0, sizeof(set->vertex_bitangent));
  24114. }
  24115. }
  24116. ufbxi_for_list(ufbx_color_set, set, result->color_sets) {
  24117. ufbxi_check_err(&sc->error, ufbxi_subdivide_attrib(sc, (ufbx_vertex_attrib*)&set->vertex_color, sc->opts.uv_boundary, true));
  24118. }
  24119. if (result->uv_sets.count > 0) {
  24120. result->vertex_uv = result->uv_sets.data[0].vertex_uv;
  24121. result->vertex_bitangent = result->uv_sets.data[0].vertex_bitangent;
  24122. result->vertex_tangent = result->uv_sets.data[0].vertex_tangent;
  24123. }
  24124. if (result->color_sets.count > 0) {
  24125. result->vertex_color = result->color_sets.data[0].vertex_color;
  24126. }
  24127. if (sc->opts.interpolate_normals && !sc->opts.ignore_normals) {
  24128. ufbxi_check_err(&sc->error, ufbxi_subdivide_attrib(sc, (ufbx_vertex_attrib*)&result->vertex_normal, sc->opts.boundary, true));
  24129. ufbxi_for_list(ufbx_vec3, normal, result->vertex_normal.values) {
  24130. *normal = ufbxi_slow_normalize3(normal);
  24131. }
  24132. if (mesh->skinned_normal.values.data == mesh->vertex_normal.values.data) {
  24133. result->skinned_normal = result->vertex_normal;
  24134. } else {
  24135. ufbxi_check_err(&sc->error, ufbxi_subdivide_attrib(sc, (ufbx_vertex_attrib*)&result->skinned_normal, sc->opts.boundary, true));
  24136. ufbxi_for_list(ufbx_vec3, normal, result->skinned_normal.values) {
  24137. *normal = ufbxi_slow_normalize3(normal);
  24138. }
  24139. }
  24140. }
  24141. if (result->vertex_crease.exists) {
  24142. ufbxi_check_err(&sc->error, ufbxi_subdivide_vertex_crease(sc, &result->vertex_crease, &mesh->vertex_crease));
  24143. }
  24144. if (mesh->skinned_position.values.data == mesh->vertex_position.values.data) {
  24145. result->skinned_position = result->vertex_position;
  24146. } else {
  24147. ufbxi_check_err(&sc->error, ufbxi_subdivide_attrib(sc, (ufbx_vertex_attrib*)&result->skinned_position, sc->opts.boundary, false));
  24148. }
  24149. ufbx_subdivision_result *result_sub = ufbxi_push_zero(&sc->result, ufbx_subdivision_result, 1);
  24150. ufbxi_check_err(&sc->error, result_sub);
  24151. result->subdivision_result = result_sub;
  24152. if (sc->opts.evaluate_source_vertices || sc->opts.evaluate_skin_weights) {
  24153. ufbx_subdivision_result *mesh_sub = mesh->subdivision_result;
  24154. ufbx_skin_deformer *skin = NULL;
  24155. if (sc->opts.evaluate_skin_weights) {
  24156. if (mesh->skin_deformers.count > 0) {
  24157. ufbxi_check_err(&sc->error, sc->opts.skin_deformer_index < mesh->skin_deformers.count);
  24158. skin = mesh->skin_deformers.data[sc->opts.skin_deformer_index];
  24159. }
  24160. }
  24161. size_t max_weights = 0;
  24162. if (sc->opts.evaluate_source_vertices) {
  24163. max_weights = ufbxi_max_sz(max_weights, mesh->num_vertices);
  24164. }
  24165. if (skin) {
  24166. max_weights = ufbxi_max_sz(max_weights, skin->clusters.count);
  24167. }
  24168. sc->tmp_vertex_weights = ufbxi_push_zero(&sc->tmp, ufbx_real, mesh->num_vertices);
  24169. sc->tmp_weights = ufbxi_push(&sc->tmp, ufbx_subdivision_weight, max_weights);
  24170. ufbxi_check_err(&sc->error, sc->tmp_vertex_weights && sc->tmp_weights);
  24171. if (sc->opts.evaluate_source_vertices) {
  24172. sc->max_vertex_weights = sc->opts.max_source_vertices ? sc->opts.max_source_vertices : SIZE_MAX;
  24173. ufbxi_subdivision_vertex_weights *weights;
  24174. if (mesh_sub && mesh_sub->source_vertex_ranges.count > 0) {
  24175. weights = ufbxi_subdivision_copy_weights(sc, mesh_sub->source_vertex_ranges, mesh_sub->source_vertex_weights);
  24176. } else {
  24177. weights = ufbxi_init_source_vertex_weights(sc, mesh->num_vertices);
  24178. }
  24179. ufbxi_check_err(&sc->error, ufbxi_subdivide_weights(sc, &result_sub->source_vertex_ranges, &result_sub->source_vertex_weights, weights));
  24180. }
  24181. if (skin) {
  24182. sc->max_vertex_weights = sc->opts.max_skin_weights ? sc->opts.max_skin_weights : SIZE_MAX;
  24183. ufbxi_subdivision_vertex_weights *weights;
  24184. if (mesh_sub && mesh_sub->source_vertex_ranges.count > 0) {
  24185. weights = ufbxi_subdivision_copy_weights(sc, mesh_sub->skin_cluster_ranges, mesh_sub->skin_cluster_weights);
  24186. } else {
  24187. weights = ufbxi_init_skin_weights(sc, mesh->num_vertices, skin);
  24188. }
  24189. ufbxi_check_err(&sc->error, ufbxi_subdivide_weights(sc, &result_sub->skin_cluster_ranges, &result_sub->skin_cluster_weights, weights));
  24190. }
  24191. }
  24192. result->num_vertices = result->vertex_position.values.count;
  24193. result->num_indices = mesh->num_indices * 4;
  24194. result->num_faces = mesh->num_indices;
  24195. result->num_triangles = mesh->num_indices * 2;
  24196. result->vertex_indices.data = result->vertex_position.indices.data;
  24197. result->vertex_indices.count = result->num_indices;
  24198. result->vertices.data = result->vertex_position.values.data;
  24199. result->vertices.count = result->num_vertices;
  24200. result->faces.count = result->num_faces;
  24201. result->faces.data = ufbxi_push(&sc->result, ufbx_face, result->num_faces);
  24202. ufbxi_check_err(&sc->error, result->faces.data);
  24203. for (size_t i = 0; i < result->num_faces; i++) {
  24204. result->faces.data[i].index_begin = (uint32_t)(i * 4);
  24205. result->faces.data[i].num_indices = 4;
  24206. }
  24207. if (mesh->edges.data) {
  24208. result->num_edges = mesh->num_edges*2 + result->num_faces;
  24209. result->edges.count = result->num_edges;
  24210. result->edges.data = ufbxi_push(&sc->result, ufbx_edge, result->num_edges);
  24211. ufbxi_check_err(&sc->error, result->edges.data);
  24212. if (mesh->edge_crease.data) {
  24213. result->edge_crease.count = result->num_edges;
  24214. result->edge_crease.data = ufbxi_push(&sc->result, ufbx_real, result->num_edges);
  24215. ufbxi_check_err(&sc->error, result->edge_crease.data);
  24216. }
  24217. if (mesh->edge_smoothing.data) {
  24218. result->edge_smoothing.count = result->num_edges;
  24219. result->edge_smoothing.data = ufbxi_push(&sc->result, bool, result->num_edges);
  24220. ufbxi_check_err(&sc->error, result->edge_smoothing.data);
  24221. }
  24222. if (mesh->edge_visibility.data) {
  24223. result->edge_visibility.count = result->num_edges;
  24224. result->edge_visibility.data = ufbxi_push(&sc->result, bool, result->num_edges);
  24225. ufbxi_check_err(&sc->error, result->edge_visibility.data);
  24226. }
  24227. size_t di = 0;
  24228. for (size_t i = 0; i < mesh->num_edges; i++) {
  24229. ufbx_edge edge = mesh->edges.data[i];
  24230. uint32_t face_ix = topo[edge.a].face;
  24231. ufbx_face face = mesh->faces.data[face_ix];
  24232. uint32_t offset = edge.a - face.index_begin;
  24233. uint32_t next = (offset + 1) % (uint32_t)face.num_indices;
  24234. uint32_t a = (face.index_begin + offset) * 4;
  24235. uint32_t b = (face.index_begin + next) * 4;
  24236. result->edges.data[di + 0].a = a;
  24237. result->edges.data[di + 0].b = a + 1;
  24238. result->edges.data[di + 1].a = b + 3;
  24239. result->edges.data[di + 1].b = b;
  24240. if (mesh->edge_crease.data) {
  24241. ufbx_real crease = mesh->edge_crease.data[i];
  24242. if (crease < 0.999f) crease -= (ufbx_real)0.1;
  24243. if (crease < 0.0f) crease = 0.0f;
  24244. result->edge_crease.data[di + 0] = crease;
  24245. result->edge_crease.data[di + 1] = crease;
  24246. }
  24247. if (mesh->edge_smoothing.data) {
  24248. result->edge_smoothing.data[di + 0] = mesh->edge_smoothing.data[i];
  24249. result->edge_smoothing.data[di + 1] = mesh->edge_smoothing.data[i];
  24250. }
  24251. if (mesh->edge_visibility.data) {
  24252. result->edge_visibility.data[di + 0] = mesh->edge_visibility.data[i];
  24253. result->edge_visibility.data[di + 1] = mesh->edge_visibility.data[i];
  24254. }
  24255. di += 2;
  24256. }
  24257. for (size_t fi = 0; fi < result->num_faces; fi++) {
  24258. result->edges.data[di].a = (uint32_t)(fi * 4 + 1);
  24259. result->edges.data[di].b = (uint32_t)(fi * 4 + 2);
  24260. if (result->edge_crease.data) {
  24261. result->edge_crease.data[di] = 0.0f;
  24262. }
  24263. if (result->edge_smoothing.data) {
  24264. result->edge_smoothing.data[di + 0] = true;
  24265. }
  24266. if (result->edge_visibility.data) {
  24267. result->edge_visibility.data[di + 0] = false;
  24268. }
  24269. di++;
  24270. }
  24271. }
  24272. if (mesh->face_material.data) {
  24273. result->face_material.count = result->num_faces;
  24274. result->face_material.data = ufbxi_push(&sc->result, uint32_t, result->num_faces);
  24275. ufbxi_check_err(&sc->error, result->face_material.data);
  24276. }
  24277. if (mesh->face_smoothing.data) {
  24278. result->face_smoothing.count = result->num_faces;
  24279. result->face_smoothing.data = ufbxi_push(&sc->result, bool, result->num_faces);
  24280. ufbxi_check_err(&sc->error, result->face_smoothing.data);
  24281. }
  24282. if (mesh->face_group.data) {
  24283. result->face_group.count = result->num_faces;
  24284. result->face_group.data = ufbxi_push(&sc->result, uint32_t, result->num_faces);
  24285. ufbxi_check_err(&sc->error, result->face_group.data);
  24286. }
  24287. if (mesh->face_hole.data) {
  24288. result->face_hole.count = result->num_faces;
  24289. result->face_hole.data = ufbxi_push(&sc->result, bool, result->num_faces);
  24290. ufbxi_check_err(&sc->error, result->face_hole.data);
  24291. }
  24292. if (result->material_parts.count > 0) {
  24293. result->material_parts.data = ufbxi_push_zero(&sc->result, ufbx_mesh_part, result->material_parts.count);
  24294. ufbxi_check_err(&sc->error, result->materials.data);
  24295. }
  24296. size_t index_offset = 0;
  24297. for (size_t i = 0; i < mesh->num_faces; i++) {
  24298. ufbx_face face = mesh->faces.data[i];
  24299. uint32_t mat = 0;
  24300. if (mesh->face_material.data) {
  24301. mat = mesh->face_material.data[i];
  24302. for (size_t ci = 0; ci < face.num_indices; ci++) {
  24303. result->face_material.data[index_offset + ci] = mat;
  24304. }
  24305. }
  24306. if (mesh->face_smoothing.data) {
  24307. bool flag = mesh->face_smoothing.data[i];
  24308. for (size_t ci = 0; ci < face.num_indices; ci++) {
  24309. result->face_smoothing.data[index_offset + ci] = flag;
  24310. }
  24311. }
  24312. if (mesh->face_group.data) {
  24313. uint32_t group = mesh->face_group.data[i];
  24314. for (size_t ci = 0; ci < face.num_indices; ci++) {
  24315. result->face_group.data[index_offset + ci] = group;
  24316. }
  24317. }
  24318. if (mesh->face_hole.data) {
  24319. bool flag = mesh->face_hole.data[i];
  24320. for (size_t ci = 0; ci < face.num_indices; ci++) {
  24321. result->face_hole.data[index_offset + ci] = flag;
  24322. }
  24323. }
  24324. index_offset += face.num_indices;
  24325. }
  24326. // Will be filled in by `ufbxi_finalize_mesh()`.
  24327. result->vertex_first_index.count = 0;
  24328. ufbxi_check_err(&sc->error, ufbxi_finalize_mesh_material(&sc->result, &sc->error, result));
  24329. ufbxi_check_err(&sc->error, ufbxi_finalize_mesh(&sc->result, &sc->error, result));
  24330. ufbxi_check_err(&sc->error, ufbxi_update_face_groups(&sc->result, &sc->error, result, true));
  24331. return 1;
  24332. }
  24333. ufbxi_nodiscard static ufbxi_noinline int ufbxi_subdivide_mesh_imp(ufbxi_subdivide_context *sc, size_t level)
  24334. {
  24335. if (sc->opts.boundary == UFBX_SUBDIVISION_BOUNDARY_DEFAULT) {
  24336. sc->opts.boundary = sc->src_mesh.subdivision_boundary;
  24337. }
  24338. if (sc->opts.uv_boundary == UFBX_SUBDIVISION_BOUNDARY_DEFAULT) {
  24339. sc->opts.uv_boundary = sc->src_mesh.subdivision_uv_boundary;
  24340. }
  24341. ufbxi_init_ator(&sc->error, &sc->ator_tmp, &sc->opts.temp_allocator, "temp");
  24342. ufbxi_init_ator(&sc->error, &sc->ator_result, &sc->opts.result_allocator, "result");
  24343. sc->result.unordered = true;
  24344. sc->source.unordered = true;
  24345. sc->tmp.unordered = true;
  24346. sc->source.ator = &sc->ator_tmp;
  24347. sc->tmp.ator = &sc->ator_tmp;
  24348. for (size_t i = 1; i < level; i++) {
  24349. sc->result.ator = &sc->ator_tmp;
  24350. ufbxi_check_err(&sc->error, ufbxi_subdivide_mesh_level(sc));
  24351. sc->src_mesh = sc->dst_mesh;
  24352. ufbxi_buf_free(&sc->source);
  24353. ufbxi_buf_free(&sc->tmp);
  24354. sc->source = sc->result;
  24355. memset(&sc->result, 0, sizeof(sc->result));
  24356. }
  24357. sc->result.ator = &sc->ator_result;
  24358. ufbxi_check_err(&sc->error, ufbxi_subdivide_mesh_level(sc));
  24359. ufbxi_buf_free(&sc->tmp);
  24360. ufbx_mesh *mesh = &sc->dst_mesh;
  24361. // Subdivision always results in a mesh that consists only of quads
  24362. mesh->max_face_triangles = 2;
  24363. mesh->num_empty_faces = 0;
  24364. mesh->num_point_faces = 0;
  24365. mesh->num_line_faces = 0;
  24366. if (!sc->opts.interpolate_normals) {
  24367. memset(&mesh->vertex_normal, 0, sizeof(mesh->vertex_normal));
  24368. memset(&mesh->skinned_normal, 0, sizeof(mesh->skinned_normal));
  24369. }
  24370. if (!sc->opts.interpolate_normals && !sc->opts.ignore_normals) {
  24371. ufbx_topo_edge *topo = ufbxi_push(&sc->tmp, ufbx_topo_edge, mesh->num_indices);
  24372. ufbxi_check_err(&sc->error, topo);
  24373. ufbx_compute_topology(mesh, topo, mesh->num_indices);
  24374. uint32_t *normal_indices = ufbxi_push(&sc->result, uint32_t, mesh->num_indices);
  24375. ufbxi_check_err(&sc->error, normal_indices);
  24376. size_t num_normals = ufbx_generate_normal_mapping(mesh, topo, mesh->num_indices, normal_indices, mesh->num_indices, true);
  24377. if (num_normals == mesh->num_vertices) {
  24378. mesh->skinned_normal.unique_per_vertex = true;
  24379. }
  24380. ufbx_vec3 *normal_data = ufbxi_push(&sc->result, ufbx_vec3, num_normals + 1);
  24381. ufbxi_check_err(&sc->error, normal_data);
  24382. normal_data[0] = ufbx_zero_vec3;
  24383. normal_data++;
  24384. ufbx_compute_normals(mesh, &mesh->skinned_position, normal_indices, mesh->num_indices, normal_data, num_normals);
  24385. mesh->generated_normals = true;
  24386. mesh->vertex_normal.exists = true;
  24387. mesh->vertex_normal.values.data = normal_data;
  24388. mesh->vertex_normal.values.count = num_normals;
  24389. mesh->vertex_normal.indices.data = normal_indices;
  24390. mesh->vertex_normal.indices.count = mesh->num_indices;
  24391. mesh->skinned_normal = mesh->vertex_normal;
  24392. }
  24393. ufbxi_refcount *parent = NULL;
  24394. if (sc->src_mesh_ptr->subdivision_evaluated && sc->src_mesh_ptr->from_tessellated_nurbs) {
  24395. parent = &(ufbxi_get_imp(ufbxi_mesh_imp, sc->src_mesh_ptr))->refcount;
  24396. } else {
  24397. parent = &(ufbxi_get_imp(ufbxi_scene_imp, sc->src_mesh_ptr->element.scene))->refcount;
  24398. }
  24399. ufbxi_patch_mesh_reals(mesh);
  24400. sc->imp = ufbxi_push(&sc->result, ufbxi_mesh_imp, 1);
  24401. ufbxi_check_err(&sc->error, sc->imp);
  24402. sc->dst_mesh.subdivision_result->result_memory_used = sc->ator_result.current_size;
  24403. sc->dst_mesh.subdivision_result->temp_memory_used = sc->ator_tmp.current_size;
  24404. sc->dst_mesh.subdivision_result->result_allocs = sc->ator_result.num_allocs;
  24405. sc->dst_mesh.subdivision_result->temp_allocs = sc->ator_tmp.num_allocs;
  24406. ufbxi_init_ref(&sc->imp->refcount, UFBXI_MESH_IMP_MAGIC, parent);
  24407. sc->imp->magic = UFBXI_MESH_IMP_MAGIC;
  24408. sc->imp->mesh = sc->dst_mesh;
  24409. sc->imp->refcount.ator = sc->ator_result;
  24410. sc->imp->refcount.buf = sc->result;
  24411. sc->imp->mesh.subdivision_evaluated = true;
  24412. return 1;
  24413. }
  24414. ufbxi_noinline static ufbx_mesh *ufbxi_subdivide_mesh(const ufbx_mesh *mesh, size_t level, const ufbx_subdivide_opts *user_opts, ufbx_error *p_error)
  24415. {
  24416. ufbxi_subdivide_context sc = { 0 };
  24417. if (user_opts) {
  24418. sc.opts = *user_opts;
  24419. }
  24420. sc.src_mesh_ptr = (ufbx_mesh*)mesh;
  24421. sc.src_mesh = *mesh;
  24422. int ok = ufbxi_subdivide_mesh_imp(&sc, level);
  24423. ufbxi_free(&sc.ator_tmp, ufbxi_subdivide_input, sc.inputs, sc.inputs_cap);
  24424. ufbxi_buf_free(&sc.tmp);
  24425. ufbxi_buf_free(&sc.source);
  24426. if (ok) {
  24427. ufbxi_free_ator(&sc.ator_tmp);
  24428. if (p_error) {
  24429. ufbxi_clear_error(p_error);
  24430. }
  24431. ufbxi_mesh_imp *imp = sc.imp;
  24432. return &imp->mesh;
  24433. } else {
  24434. ufbxi_fix_error_type(&sc.error, "Failed to subdivide");
  24435. if (p_error) *p_error = sc.error;
  24436. ufbxi_buf_free(&sc.result);
  24437. ufbxi_free_ator(&sc.ator_tmp);
  24438. ufbxi_free_ator(&sc.ator_result);
  24439. return NULL;
  24440. }
  24441. }
  24442. #else
  24443. ufbxi_noinline static ufbx_mesh *ufbxi_subdivide_mesh(const ufbx_mesh *mesh, size_t level, const ufbx_subdivide_opts *user_opts, ufbx_error *p_error)
  24444. {
  24445. if (p_error) {
  24446. memset(p_error, 0, sizeof(ufbx_error));
  24447. ufbxi_fmt_err_info(p_error, "UFBX_ENABLE_SUBDIVISION");
  24448. ufbxi_report_err_msg(p_error, "UFBXI_FEATURE_SUBDIVISION", "Feature disabled");
  24449. }
  24450. return NULL;
  24451. }
  24452. #endif
  24453. // -- Utility
  24454. #if UFBXI_FEATURE_INDEX_GENERATION
  24455. static int ufbxi_map_cmp_vertex(void *user, const void *va, const void *vb)
  24456. {
  24457. size_t size = *(size_t*)user;
  24458. #if defined(UFBX_REGRESSION)
  24459. ufbx_assert(size % 8 == 0);
  24460. #endif
  24461. for (size_t i = 0; i < size; i += 8) {
  24462. uint64_t a = *(const uint64_t*)((const char*)va + i);
  24463. uint64_t b = *(const uint64_t*)((const char*)vb + i);
  24464. if (a != b) return a < b ? -1 : +1;
  24465. }
  24466. return 0;
  24467. }
  24468. typedef struct {
  24469. char *begin, *ptr;
  24470. size_t vertex_size;
  24471. size_t packed_offset;
  24472. } ufbxi_vertex_stream;
  24473. static ufbxi_noinline size_t ufbxi_generate_indices(const ufbx_vertex_stream *user_streams, size_t num_streams, uint32_t *indices, size_t num_indices, const ufbx_allocator_opts *allocator, ufbx_error *error)
  24474. {
  24475. bool fail = false;
  24476. ufbxi_allocator ator = { 0 };
  24477. ufbxi_init_ator(error, &ator, allocator, "allocator");
  24478. ufbxi_vertex_stream local_streams[16]; // ufbxi_uninit
  24479. uint64_t local_packed_vertex[64]; // ufbxi_uninit
  24480. ufbxi_vertex_stream *streams = NULL;
  24481. if (num_streams > ufbxi_arraycount(local_streams)) {
  24482. streams = ufbxi_alloc(&ator, ufbxi_vertex_stream, num_streams);
  24483. if (!streams) fail = true;
  24484. } else {
  24485. streams = local_streams;
  24486. }
  24487. size_t packed_size = 0;
  24488. if (!fail) {
  24489. for (size_t i = 0; i < num_streams; i++) {
  24490. if (user_streams[i].vertex_count < num_indices) {
  24491. ufbxi_fmt_err_info(error, "%zu", i);
  24492. ufbxi_report_err_msg(error, "user_streams[i].vertex_count < num_indices", "Truncated vertex stream");
  24493. fail = true;
  24494. break;
  24495. }
  24496. size_t vertex_size = user_streams[i].vertex_size;
  24497. size_t align = ufbxi_size_align_mask(vertex_size);
  24498. packed_size = ufbxi_align_to_mask(packed_size, align);
  24499. streams[i].ptr = streams[i].begin = (char*)user_streams[i].data;
  24500. streams[i].vertex_size = vertex_size;
  24501. streams[i].packed_offset = packed_size;
  24502. packed_size += vertex_size;
  24503. }
  24504. packed_size = ufbxi_align_to_mask(packed_size, 7);
  24505. }
  24506. if (!fail && packed_size == 0) {
  24507. ufbxi_report_err_msg(error, "packed_size != 0", "Zero vertex size");
  24508. fail = true;
  24509. }
  24510. char *packed_vertex = NULL;
  24511. if (!fail) {
  24512. if (packed_size > sizeof(local_packed_vertex)) {
  24513. ufbx_assert(packed_size % 8 == 0);
  24514. packed_vertex = (char*)ufbxi_alloc(&ator, uint64_t, packed_size / 8);
  24515. if (!packed_vertex) fail = true;
  24516. } else {
  24517. packed_vertex = (char*)local_packed_vertex;
  24518. }
  24519. }
  24520. ufbxi_map map = { 0 };
  24521. ufbxi_map_init(&map, &ator, &ufbxi_map_cmp_vertex, &packed_size);
  24522. if (num_indices > 0 && !ufbxi_map_grow_size(&map, packed_size, num_indices)) {
  24523. fail = true;
  24524. }
  24525. if (!fail) {
  24526. ufbx_assert(packed_vertex != NULL);
  24527. memset(packed_vertex, 0, packed_size);
  24528. for (size_t i = 0; i < num_indices; i++) {
  24529. for (size_t si = 0; si < num_streams; si++) {
  24530. size_t size = streams[si].vertex_size, offset = streams[si].packed_offset;
  24531. char *ptr = streams[si].ptr;
  24532. memcpy(packed_vertex + offset, ptr, size);
  24533. streams[si].ptr = ptr + size;
  24534. }
  24535. uint32_t hash = ufbxi_hash_string(packed_vertex, packed_size);
  24536. void *entry = ufbxi_map_find_size(&map, packed_size, hash, packed_vertex);
  24537. if (!entry) {
  24538. entry = ufbxi_map_insert_size(&map, packed_size, hash, packed_vertex);
  24539. if (!entry) {
  24540. fail = true;
  24541. break;
  24542. }
  24543. memcpy(entry, packed_vertex, packed_size);
  24544. }
  24545. uint32_t index = (uint32_t)(ufbxi_to_size((char*)entry - (char*)map.items) / packed_size);
  24546. indices[i] = index;
  24547. }
  24548. }
  24549. size_t result_vertices = 0;
  24550. if (!fail) {
  24551. result_vertices = map.size;
  24552. for (size_t si = 0; si < num_streams; si++) {
  24553. size_t vertex_size = streams[si].vertex_size;
  24554. char *dst = streams[si].begin;
  24555. char *src = ufbxi_add_ptr((char*)map.items, streams[si].packed_offset);
  24556. for (size_t i = 0; i < result_vertices; i++) {
  24557. memcpy(dst, src, vertex_size);
  24558. dst += vertex_size;
  24559. src += packed_size;
  24560. }
  24561. }
  24562. ufbxi_clear_error(error);
  24563. } else {
  24564. ufbxi_fix_error_type(error, "Failed to generate indices");
  24565. }
  24566. if (streams && streams != local_streams) {
  24567. ufbxi_free(&ator, ufbxi_vertex_stream, streams, num_streams);
  24568. }
  24569. if (packed_vertex && packed_vertex != (char*)local_packed_vertex) {
  24570. ufbxi_free(&ator, uint64_t, packed_vertex, packed_size / 8);
  24571. }
  24572. ufbxi_map_free(&map);
  24573. ufbxi_free_ator(&ator);
  24574. return result_vertices;
  24575. }
  24576. #else
  24577. static ufbxi_noinline size_t ufbxi_generate_indices(const ufbx_vertex_stream *user_streams, size_t num_streams, uint32_t *indices, size_t num_indices, const ufbx_allocator_opts *allocator, ufbx_error *error)
  24578. {
  24579. if (error) {
  24580. memset(error, 0, sizeof(ufbx_error));
  24581. ufbxi_fmt_err_info(error, "UFBX_ENABLE_INDEX_GENERATION");
  24582. ufbxi_report_err_msg(error, "UFBXI_FEATURE_INDEX_GENERATION", "Feature disabled");
  24583. }
  24584. return 0;
  24585. }
  24586. #endif
  24587. static ufbxi_noinline void ufbxi_free_scene_imp(ufbxi_scene_imp *imp)
  24588. {
  24589. ufbx_assert(imp->magic == UFBXI_SCENE_IMP_MAGIC);
  24590. ufbxi_buf_free(&imp->string_buf);
  24591. }
  24592. static ufbxi_noinline void ufbxi_init_ref(ufbxi_refcount *refcount, uint32_t magic, ufbxi_refcount *parent)
  24593. {
  24594. if (parent) {
  24595. ufbxi_retain_ref(parent);
  24596. }
  24597. ufbxi_atomic_counter_init(&refcount->refcount);
  24598. refcount->self_magic = UFBXI_REFCOUNT_IMP_MAGIC;
  24599. refcount->type_magic = magic;
  24600. refcount->parent = parent;
  24601. }
  24602. static ufbxi_noinline void ufbxi_retain_ref(ufbxi_refcount *refcount)
  24603. {
  24604. ufbx_assert(refcount->self_magic == UFBXI_REFCOUNT_IMP_MAGIC);
  24605. size_t count = ufbxi_atomic_counter_inc(&refcount->refcount);
  24606. ufbxi_ignore(count);
  24607. ufbx_assert(count < SIZE_MAX / 2);
  24608. }
  24609. static ufbxi_noinline void ufbxi_release_ref(ufbxi_refcount *refcount)
  24610. {
  24611. while (refcount) {
  24612. ufbx_assert(refcount->self_magic == UFBXI_REFCOUNT_IMP_MAGIC);
  24613. if (ufbxi_atomic_counter_dec(&refcount->refcount) > 0) return;
  24614. ufbxi_atomic_counter_free(&refcount->refcount);
  24615. ufbxi_refcount *parent = refcount->parent;
  24616. uint32_t type_magic = refcount->type_magic;
  24617. refcount->self_magic = 0;
  24618. refcount->type_magic = 0;
  24619. // Type-specific cleanup
  24620. switch (type_magic) {
  24621. case UFBXI_SCENE_IMP_MAGIC: ufbxi_free_scene_imp((ufbxi_scene_imp*)refcount); break;
  24622. case UFBXI_CACHE_IMP_MAGIC: ufbxi_free_geometry_cache_imp((ufbxi_geometry_cache_imp*)refcount); break;
  24623. default: break;
  24624. }
  24625. // We need to free `data_buf` last and be careful to copy it to
  24626. // the stack since the `ufbxi_refcount` that contains it is allocated
  24627. // from the same result buffer!
  24628. ufbxi_allocator ator = refcount->ator;
  24629. ufbxi_buf buf = refcount->buf;
  24630. buf.ator = &ator;
  24631. ufbxi_buf_free(&buf);
  24632. ufbxi_free_ator(&ator);
  24633. refcount = parent;
  24634. }
  24635. }
  24636. static ufbxi_noinline void *ufbxi_uninitialized_options(ufbx_error *p_error)
  24637. {
  24638. if (p_error) {
  24639. memset(p_error, 0, sizeof(ufbx_error));
  24640. p_error->type = UFBX_ERROR_UNINITIALIZED_OPTIONS;
  24641. p_error->description.data = "Uninitialized options";
  24642. p_error->description.length = strlen("Uninitialized options");
  24643. }
  24644. return NULL;
  24645. }
  24646. #define ufbxi_check_opts_ptr(m_type, m_opts, m_error) do { if (m_opts) { \
  24647. uint32_t opts_cleared_to_zero = m_opts->_begin_zero | m_opts->_end_zero; \
  24648. ufbx_assert(opts_cleared_to_zero == 0); \
  24649. if (opts_cleared_to_zero != 0) return (m_type*)ufbxi_uninitialized_options(m_error); \
  24650. } } while (0)
  24651. #define ufbxi_check_opts_return(m_value, m_opts, m_error) do { if (m_opts) { \
  24652. uint32_t opts_cleared_to_zero = m_opts->_begin_zero | m_opts->_end_zero; \
  24653. ufbx_assert(opts_cleared_to_zero == 0); \
  24654. if (opts_cleared_to_zero != 0) { \
  24655. ufbxi_uninitialized_options(m_error); \
  24656. return m_value; \
  24657. } \
  24658. } } while (0)
  24659. #define ufbxi_check_opts_return_no_error(m_value, m_opts) do { if (m_opts) { \
  24660. uint32_t opts_cleared_to_zero = m_opts->_begin_zero | m_opts->_end_zero; \
  24661. if (opts_cleared_to_zero != 0) return m_value; \
  24662. } } while (0)
  24663. // -- API
  24664. #ifdef __cplusplus
  24665. extern "C" {
  24666. #endif
  24667. ufbx_abi_data_def const ufbx_string ufbx_empty_string = { ufbxi_empty_char, 0 };
  24668. ufbx_abi_data_def const ufbx_blob ufbx_empty_blob = { NULL, 0 };
  24669. ufbx_abi_data_def const ufbx_matrix ufbx_identity_matrix = { 1,0,0, 0,1,0, 0,0,1, 0,0,0 };
  24670. ufbx_abi_data_def const ufbx_transform ufbx_identity_transform = { {0,0,0}, {0,0,0,1}, {1,1,1} };
  24671. ufbx_abi_data_def const ufbx_vec2 ufbx_zero_vec2 = { 0,0 };
  24672. ufbx_abi_data_def const ufbx_vec3 ufbx_zero_vec3 = { 0,0,0 };
  24673. ufbx_abi_data_def const ufbx_vec4 ufbx_zero_vec4 = { 0,0,0,0 };
  24674. ufbx_abi_data_def const ufbx_quat ufbx_identity_quat = { 0,0,0,1 };
  24675. ufbx_abi_data_def const ufbx_coordinate_axes ufbx_axes_right_handed_y_up = {
  24676. UFBX_COORDINATE_AXIS_POSITIVE_X, UFBX_COORDINATE_AXIS_POSITIVE_Y, UFBX_COORDINATE_AXIS_POSITIVE_Z,
  24677. };
  24678. ufbx_abi_data_def const ufbx_coordinate_axes ufbx_axes_right_handed_z_up = {
  24679. UFBX_COORDINATE_AXIS_POSITIVE_X, UFBX_COORDINATE_AXIS_POSITIVE_Z, UFBX_COORDINATE_AXIS_NEGATIVE_Y,
  24680. };
  24681. ufbx_abi_data_def const ufbx_coordinate_axes ufbx_axes_left_handed_y_up = {
  24682. UFBX_COORDINATE_AXIS_POSITIVE_X, UFBX_COORDINATE_AXIS_POSITIVE_Y, UFBX_COORDINATE_AXIS_NEGATIVE_Z,
  24683. };
  24684. ufbx_abi_data_def const ufbx_coordinate_axes ufbx_axes_left_handed_z_up = {
  24685. UFBX_COORDINATE_AXIS_POSITIVE_X, UFBX_COORDINATE_AXIS_POSITIVE_Z, UFBX_COORDINATE_AXIS_POSITIVE_Y,
  24686. };
  24687. ufbx_abi_data_def const size_t ufbx_element_type_size[UFBX_ELEMENT_TYPE_COUNT] = {
  24688. sizeof(ufbx_unknown),
  24689. sizeof(ufbx_node),
  24690. sizeof(ufbx_mesh),
  24691. sizeof(ufbx_light),
  24692. sizeof(ufbx_camera),
  24693. sizeof(ufbx_bone),
  24694. sizeof(ufbx_empty),
  24695. sizeof(ufbx_line_curve),
  24696. sizeof(ufbx_nurbs_curve),
  24697. sizeof(ufbx_nurbs_surface),
  24698. sizeof(ufbx_nurbs_trim_surface),
  24699. sizeof(ufbx_nurbs_trim_boundary),
  24700. sizeof(ufbx_procedural_geometry),
  24701. sizeof(ufbx_stereo_camera),
  24702. sizeof(ufbx_camera_switcher),
  24703. sizeof(ufbx_marker),
  24704. sizeof(ufbx_lod_group),
  24705. sizeof(ufbx_skin_deformer),
  24706. sizeof(ufbx_skin_cluster),
  24707. sizeof(ufbx_blend_deformer),
  24708. sizeof(ufbx_blend_channel),
  24709. sizeof(ufbx_blend_shape),
  24710. sizeof(ufbx_cache_deformer),
  24711. sizeof(ufbx_cache_file),
  24712. sizeof(ufbx_material),
  24713. sizeof(ufbx_texture),
  24714. sizeof(ufbx_video),
  24715. sizeof(ufbx_shader),
  24716. sizeof(ufbx_shader_binding),
  24717. sizeof(ufbx_anim_stack),
  24718. sizeof(ufbx_anim_layer),
  24719. sizeof(ufbx_anim_value),
  24720. sizeof(ufbx_anim_curve),
  24721. sizeof(ufbx_display_layer),
  24722. sizeof(ufbx_selection_set),
  24723. sizeof(ufbx_selection_node),
  24724. sizeof(ufbx_character),
  24725. sizeof(ufbx_constraint),
  24726. sizeof(ufbx_audio_layer),
  24727. sizeof(ufbx_audio_clip),
  24728. sizeof(ufbx_pose),
  24729. sizeof(ufbx_metadata_object),
  24730. };
  24731. ufbx_abi bool ufbx_open_file(ufbx_stream *stream, const char *path, size_t path_len)
  24732. {
  24733. ufbxi_allocator tmp_ator = { 0 };
  24734. ufbx_error tmp_error = { UFBX_ERROR_NONE };
  24735. ufbxi_init_ator(&tmp_error, &tmp_ator, NULL, "filename");
  24736. FILE *f = ufbxi_fopen(path, path_len, &tmp_ator);
  24737. if (!f) return false;
  24738. stream->read_fn = &ufbxi_file_read;
  24739. stream->skip_fn = &ufbxi_file_skip;
  24740. stream->close_fn = &ufbxi_file_close;
  24741. stream->user = f;
  24742. return true;
  24743. }
  24744. ufbx_abi bool ufbx_default_open_file(void *user, ufbx_stream *stream, const char *path, size_t path_len, const ufbx_open_file_info *info)
  24745. {
  24746. (void)user;
  24747. (void)info;
  24748. return ufbx_open_file(stream, path, path_len);
  24749. }
  24750. ufbx_abi bool ufbx_open_memory(ufbx_stream *stream, const void *data, size_t data_size, const ufbx_open_memory_opts *opts, ufbx_error *error)
  24751. {
  24752. ufbx_open_memory_opts local_opts; // ufbxi_uninit
  24753. if (!opts) {
  24754. memset(&local_opts, 0, sizeof(local_opts));
  24755. opts = &local_opts;
  24756. }
  24757. ufbx_assert(opts->_begin_zero == 0 && opts->_end_zero == 0);
  24758. ufbx_error local_error = { UFBX_ERROR_NONE };
  24759. if (!error) error = &local_error;
  24760. ufbxi_clear_error(error);
  24761. ufbxi_allocator ator = { 0 };
  24762. ufbxi_init_ator(error, &ator, &opts->allocator, "memory");
  24763. size_t copy_size = opts->no_copy ? 0 : data_size;
  24764. // Align the allocation size to 8 bytes to make sure the header is aligned.
  24765. size_t self_size = ufbxi_align_to_mask(sizeof(ufbxi_memory_stream) + copy_size, 7);
  24766. void *memory = ufbxi_alloc(&ator, char, self_size);
  24767. if (!memory) {
  24768. ufbxi_free_ator(&ator);
  24769. ufbxi_fix_error_type(error, "Failed to open memory");
  24770. return false;
  24771. }
  24772. ufbxi_memory_stream *mem = (ufbxi_memory_stream*)memory;
  24773. memset(mem, 0, sizeof(ufbxi_memory_stream));
  24774. mem->size = data_size;
  24775. mem->self_size = self_size;
  24776. mem->close_cb = opts->close_cb;
  24777. if (opts->no_copy) {
  24778. mem->data = data;
  24779. } else {
  24780. memcpy(mem->data_copy, data, data_size);
  24781. mem->data = mem->data_copy;
  24782. }
  24783. // Transplant the allocator in the result blob
  24784. mem->ator = ator;
  24785. mem->ator.error = &mem->error;
  24786. stream->read_fn = ufbxi_memory_read;
  24787. stream->skip_fn = ufbxi_memory_skip;
  24788. stream->close_fn = ufbxi_memory_close;
  24789. stream->user = mem;
  24790. return true;
  24791. }
  24792. ufbx_abi bool ufbx_is_thread_safe(void)
  24793. {
  24794. return UFBXI_THREAD_SAFE != 0;
  24795. }
  24796. ufbx_abi ufbx_scene *ufbx_load_memory(const void *data, size_t size, const ufbx_load_opts *opts, ufbx_error *error)
  24797. {
  24798. ufbxi_check_opts_ptr(ufbx_scene, opts, error);
  24799. ufbxi_context uc = { UFBX_ERROR_NONE };
  24800. uc.data_begin = uc.data = (const char *)data;
  24801. uc.data_size = size;
  24802. uc.progress_bytes_total = size;
  24803. return ufbxi_load(&uc, opts, error);
  24804. }
  24805. ufbx_abi ufbx_scene *ufbx_load_file(const char *filename, const ufbx_load_opts *opts, ufbx_error *error)
  24806. {
  24807. return ufbx_load_file_len(filename, SIZE_MAX, opts, error);
  24808. }
  24809. ufbx_abi ufbx_scene *ufbx_load_file_len(const char *filename, size_t filename_len, const ufbx_load_opts *opts, ufbx_error *error)
  24810. {
  24811. ufbxi_check_opts_ptr(ufbx_scene, opts, error);
  24812. ufbx_load_opts opts_copy;
  24813. if (opts) {
  24814. opts_copy = *opts;
  24815. } else {
  24816. memset(&opts_copy, 0, sizeof(opts_copy));
  24817. opts = &opts_copy;
  24818. }
  24819. if (opts_copy.filename.length == 0 || opts_copy.filename.data == NULL) {
  24820. opts_copy.filename.data = filename;
  24821. opts_copy.filename.length = filename_len;
  24822. }
  24823. // Defer to `ufbx_load_stream()` if the user so prefers.
  24824. if (!opts->open_main_file_with_default && opts->open_file_cb.fn) {
  24825. ufbx_stream stream = { 0 };
  24826. if (ufbxi_open_file(&opts->open_file_cb, &stream, filename, filename_len, NULL, NULL, UFBX_OPEN_FILE_MAIN_MODEL)) {
  24827. return ufbx_load_stream_prefix(&stream, NULL, 0, &opts_copy, error);
  24828. } else {
  24829. return ufbxi_load_not_found(filename, filename_len, error);
  24830. }
  24831. }
  24832. ufbxi_allocator tmp_ator = { 0 };
  24833. ufbx_error tmp_error = { UFBX_ERROR_NONE };
  24834. ufbxi_init_ator(&tmp_error, &tmp_ator, opts ? &opts->temp_allocator : NULL, "filename");
  24835. FILE *file = ufbxi_fopen(filename, filename_len, &tmp_ator);
  24836. if (!file) {
  24837. return ufbxi_load_not_found(filename, filename_len, error);
  24838. }
  24839. ufbx_scene *scene = ufbx_load_stdio(file, &opts_copy, error);
  24840. fclose(file);
  24841. return scene;
  24842. }
  24843. ufbx_abi ufbx_scene *ufbx_load_stdio(void *file_void, const ufbx_load_opts *opts, ufbx_error *error)
  24844. {
  24845. return ufbx_load_stdio_prefix(file_void, NULL, 0, opts, error);
  24846. }
  24847. ufbx_abi ufbx_scene *ufbx_load_stdio_prefix(void *file_void, const void *prefix, size_t prefix_size, const ufbx_load_opts *opts, ufbx_error *error)
  24848. {
  24849. ufbxi_check_opts_ptr(ufbx_scene, opts, error);
  24850. FILE *file = (FILE*)file_void;
  24851. ufbxi_context uc = { UFBX_ERROR_NONE };
  24852. uc.data_begin = uc.data = (const char *)prefix;
  24853. uc.data_size = prefix_size;
  24854. uc.read_fn = &ufbxi_file_read;
  24855. uc.skip_fn = &ufbxi_file_skip;
  24856. uc.read_user = file;
  24857. if (opts && opts->progress_cb.fn && opts->file_size_estimate == 0) {
  24858. uint64_t begin = ufbxi_ftell(file);
  24859. if (begin < UINT64_MAX) {
  24860. fpos_t pos; // ufbxi_uninit
  24861. if (fgetpos(file, &pos) == 0) {
  24862. if (fseek(file, 0, SEEK_END) == 0) {
  24863. uint64_t end = ufbxi_ftell(file);
  24864. if (end != UINT64_MAX && begin < end) {
  24865. uc.progress_bytes_total = end - begin;
  24866. }
  24867. // Both `rewind()` and `fsetpos()` to reset error and EOF
  24868. rewind(file);
  24869. fsetpos(file, &pos);
  24870. }
  24871. }
  24872. }
  24873. }
  24874. ufbx_scene *scene = ufbxi_load(&uc, opts, error);
  24875. return scene;
  24876. }
  24877. ufbx_abi ufbx_scene *ufbx_load_stream(const ufbx_stream *stream, const ufbx_load_opts *opts, ufbx_error *error)
  24878. {
  24879. return ufbx_load_stream_prefix(stream, NULL, 0, opts, error);
  24880. }
  24881. ufbx_abi ufbx_scene *ufbx_load_stream_prefix(const ufbx_stream *stream, const void *prefix, size_t prefix_size, const ufbx_load_opts *opts, ufbx_error *error)
  24882. {
  24883. ufbxi_check_opts_ptr(ufbx_scene, opts, error);
  24884. ufbxi_context uc = { UFBX_ERROR_NONE };
  24885. uc.data_begin = uc.data = (const char *)prefix;
  24886. uc.data_size = prefix_size;
  24887. uc.read_fn = stream->read_fn;
  24888. uc.skip_fn = stream->skip_fn;
  24889. uc.close_fn = stream->close_fn;
  24890. uc.read_user = stream->user;
  24891. ufbx_scene *scene = ufbxi_load(&uc, opts, error);
  24892. return scene;
  24893. }
  24894. ufbx_abi void ufbx_free_scene(ufbx_scene *scene)
  24895. {
  24896. if (!scene) return;
  24897. ufbxi_scene_imp *imp = ufbxi_get_imp(ufbxi_scene_imp, scene);
  24898. ufbx_assert(imp->magic == UFBXI_SCENE_IMP_MAGIC);
  24899. if (imp->magic != UFBXI_SCENE_IMP_MAGIC) return;
  24900. ufbxi_release_ref(&imp->refcount);
  24901. }
  24902. ufbx_abi void ufbx_retain_scene(ufbx_scene *scene)
  24903. {
  24904. if (!scene) return;
  24905. ufbxi_scene_imp *imp = ufbxi_get_imp(ufbxi_scene_imp, scene);
  24906. ufbx_assert(imp->magic == UFBXI_SCENE_IMP_MAGIC);
  24907. if (imp->magic != UFBXI_SCENE_IMP_MAGIC) return;
  24908. ufbxi_retain_ref(&imp->refcount);
  24909. }
  24910. ufbx_abi ufbxi_noinline size_t ufbx_format_error(char *dst, size_t dst_size, const ufbx_error *error)
  24911. {
  24912. if (!dst || !dst_size) return 0;
  24913. if (!error) {
  24914. *dst = '\0';
  24915. return 0;
  24916. }
  24917. size_t offset = 0;
  24918. {
  24919. int num;
  24920. if (error->info_length > 0 && error->info_length < UFBX_ERROR_INFO_LENGTH) {
  24921. num = ufbxi_snprintf(dst + offset, dst_size - offset, "ufbx v%u.%u.%u error: %s (%.*s)\n",
  24922. UFBX_SOURCE_VERSION/1000000, UFBX_SOURCE_VERSION/1000%1000, UFBX_SOURCE_VERSION%1000,
  24923. error->description.data ? error->description.data : "Unknown error",
  24924. (int)error->info_length, error->info);
  24925. } else {
  24926. num = ufbxi_snprintf(dst + offset, dst_size - offset, "ufbx v%u.%u.%u error: %s\n",
  24927. UFBX_SOURCE_VERSION/1000000, UFBX_SOURCE_VERSION/1000%1000, UFBX_SOURCE_VERSION%1000,
  24928. error->description.data ? error->description.data : "Unknown error");
  24929. }
  24930. if (num > 0) offset = ufbxi_min_sz(offset + (size_t)num, dst_size - 1);
  24931. }
  24932. size_t stack_size = ufbxi_min_sz(error->stack_size, UFBX_ERROR_STACK_MAX_DEPTH);
  24933. for (size_t i = 0; i < stack_size; i++) {
  24934. const ufbx_error_frame *frame = &error->stack[i];
  24935. int num = ufbxi_snprintf(dst + offset, dst_size - offset, "%6u:%s: %s\n", frame->source_line, frame->function.data, frame->description.data);
  24936. if (num > 0) offset = ufbxi_min_sz(offset + (size_t)num, dst_size - 1);
  24937. }
  24938. return offset;
  24939. }
  24940. ufbx_abi ufbx_prop *ufbx_find_prop_len(const ufbx_props *props, const char *name, size_t name_len)
  24941. {
  24942. uint32_t key = ufbxi_get_name_key(name, name_len);
  24943. ufbx_string name_str = ufbxi_safe_string(name, name_len);
  24944. while (props) {
  24945. size_t index = SIZE_MAX;
  24946. ufbxi_macro_lower_bound_eq(ufbx_prop, 4, &index, props->props.data, 0, props->props.count,
  24947. ( ufbxi_cmp_prop_less_ref(a, name_str, key) ), ( a->_internal_key == key && ufbxi_str_equal(a->name, name_str) ));
  24948. if (index != SIZE_MAX) return &props->props.data[index];
  24949. props = props->defaults;
  24950. }
  24951. return NULL;
  24952. }
  24953. ufbx_abi ufbx_real ufbx_find_real_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_real def)
  24954. {
  24955. ufbx_prop *prop = ufbx_find_prop_len(props, name, name_len);
  24956. if (prop) {
  24957. return prop->value_real;
  24958. } else {
  24959. return def;
  24960. }
  24961. }
  24962. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_find_vec3_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_vec3 def)
  24963. {
  24964. ufbx_prop *prop = ufbx_find_prop_len(props, name, name_len);
  24965. if (prop) {
  24966. return prop->value_vec3;
  24967. } else {
  24968. return def;
  24969. }
  24970. }
  24971. ufbx_abi ufbxi_noinline int64_t ufbx_find_int_len(const ufbx_props *props, const char *name, size_t name_len, int64_t def)
  24972. {
  24973. ufbx_prop *prop = ufbx_find_prop_len(props, name, name_len);
  24974. if (prop) {
  24975. return prop->value_int;
  24976. } else {
  24977. return def;
  24978. }
  24979. }
  24980. ufbx_abi bool ufbx_find_bool_len(const ufbx_props *props, const char *name, size_t name_len, bool def)
  24981. {
  24982. ufbx_prop *prop = ufbx_find_prop_len(props, name, name_len);
  24983. if (prop) {
  24984. return prop->value_int != 0;
  24985. } else {
  24986. return def;
  24987. }
  24988. }
  24989. ufbx_abi ufbxi_noinline ufbx_string ufbx_find_string_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_string def)
  24990. {
  24991. ufbx_prop *prop = ufbx_find_prop_len(props, name, name_len);
  24992. if (prop) {
  24993. return prop->value_str;
  24994. } else {
  24995. return def;
  24996. }
  24997. }
  24998. ufbx_abi ufbx_blob ufbx_find_blob_len(const ufbx_props *props, const char *name, size_t name_len, ufbx_blob def)
  24999. {
  25000. ufbx_prop *prop = ufbx_find_prop_len(props, name, name_len);
  25001. if (prop) {
  25002. return prop->value_blob;
  25003. } else {
  25004. return def;
  25005. }
  25006. }
  25007. ufbx_abi ufbx_prop *ufbx_find_prop_concat(const ufbx_props *props, const ufbx_string *parts, size_t num_parts)
  25008. {
  25009. uint32_t key = ufbxi_get_concat_key(parts, num_parts);
  25010. while (props) {
  25011. size_t index = SIZE_MAX;
  25012. ufbxi_macro_lower_bound_eq(ufbx_prop, 2, &index, props->props.data, 0, props->props.count,
  25013. ( ufbxi_cmp_prop_less_concat(a, parts, num_parts, key) ),
  25014. ( a->_internal_key == key && ufbxi_concat_str_cmp(&a->name, parts, num_parts) == 0 ));
  25015. if (index != SIZE_MAX) return &props->props.data[index];
  25016. props = props->defaults;
  25017. }
  25018. return NULL;
  25019. }
  25020. ufbx_abi ufbx_element *ufbx_find_element_len(const ufbx_scene *scene, ufbx_element_type type, const char *name, size_t name_len)
  25021. {
  25022. if (!scene) return NULL;
  25023. ufbx_string name_str = ufbxi_safe_string(name, name_len);
  25024. uint32_t key = ufbxi_get_name_key(name, name_len);
  25025. size_t index = SIZE_MAX;
  25026. ufbxi_macro_lower_bound_eq(ufbx_name_element, 16, &index, scene->elements_by_name.data, 0, scene->elements_by_name.count,
  25027. ( ufbxi_cmp_name_element_less_ref(a, name_str, type, key) ), ( ufbxi_str_equal(a->name, name_str) && a->type == type ));
  25028. return index < SIZE_MAX ? scene->elements_by_name.data[index].element : NULL;
  25029. }
  25030. ufbx_abi ufbx_element *ufbx_get_prop_element(const ufbx_element *element, const ufbx_prop *prop, ufbx_element_type type)
  25031. {
  25032. ufbx_assert(element && prop);
  25033. if (!element || !prop) return NULL;
  25034. return ufbxi_fetch_dst_element((ufbx_element*)element, false, prop->name.data, type);
  25035. }
  25036. ufbx_abi ufbx_element *ufbx_find_prop_element_len(const ufbx_element *element, const char *name, size_t name_len, ufbx_element_type type)
  25037. {
  25038. const ufbx_prop *prop = ufbx_find_prop_len(&element->props, name, name_len);
  25039. if (prop) {
  25040. return ufbx_get_prop_element(element, prop, type);
  25041. } else {
  25042. return NULL;
  25043. }
  25044. }
  25045. ufbx_abi ufbx_node *ufbx_find_node_len(const ufbx_scene *scene, const char *name, size_t name_len)
  25046. {
  25047. return (ufbx_node*)ufbx_find_element_len(scene, UFBX_ELEMENT_NODE, name, name_len);
  25048. }
  25049. ufbx_abi ufbx_anim_stack *ufbx_find_anim_stack_len(const ufbx_scene *scene, const char *name, size_t name_len)
  25050. {
  25051. return (ufbx_anim_stack*)ufbx_find_element_len(scene, UFBX_ELEMENT_ANIM_STACK, name, name_len);
  25052. }
  25053. ufbx_abi ufbx_material *ufbx_find_material_len(const ufbx_scene *scene, const char *name, size_t name_len)
  25054. {
  25055. return (ufbx_material*)ufbx_find_element_len(scene, UFBX_ELEMENT_MATERIAL, name, name_len);
  25056. }
  25057. ufbx_abi ufbx_anim_prop *ufbx_find_anim_prop_len(const ufbx_anim_layer *layer, const ufbx_element *element, const char *prop, size_t prop_len)
  25058. {
  25059. ufbx_assert(layer);
  25060. ufbx_assert(element);
  25061. if (!layer || !element) return NULL;
  25062. ufbx_string prop_str = ufbxi_safe_string(prop, prop_len);
  25063. size_t index = SIZE_MAX;
  25064. ufbxi_macro_lower_bound_eq(ufbx_anim_prop, 16, &index, layer->anim_props.data, 0, layer->anim_props.count,
  25065. ( a->element != element ? a->element < element : ufbxi_str_less(a->prop_name, prop_str) ),
  25066. ( a->element == element && ufbxi_str_equal(a->prop_name, prop_str) ));
  25067. if (index == SIZE_MAX) return NULL;
  25068. return &layer->anim_props.data[index];
  25069. }
  25070. ufbx_abi ufbxi_noinline ufbx_anim_prop_list ufbx_find_anim_props(const ufbx_anim_layer *layer, const ufbx_element *element)
  25071. {
  25072. ufbx_anim_prop_list result = { 0 };
  25073. ufbx_assert(layer);
  25074. ufbx_assert(element);
  25075. if (!layer || !element) return result;
  25076. size_t begin = layer->anim_props.count, end = begin;
  25077. ufbxi_macro_lower_bound_eq(ufbx_anim_prop, 16, &begin, layer->anim_props.data, 0, layer->anim_props.count,
  25078. ( a->element < element ), ( a->element == element ));
  25079. ufbxi_macro_upper_bound_eq(ufbx_anim_prop, 16, &end, layer->anim_props.data, begin, layer->anim_props.count,
  25080. ( a->element == element ));
  25081. if (begin != end) {
  25082. result.data = layer->anim_props.data + begin;
  25083. result.count = end - begin;
  25084. }
  25085. return result;
  25086. }
  25087. ufbx_abi ufbxi_noinline ufbx_matrix ufbx_get_compatible_matrix_for_normals(const ufbx_node *node)
  25088. {
  25089. if (!node) return ufbx_identity_matrix;
  25090. ufbx_transform geom_rot = ufbx_identity_transform;
  25091. geom_rot.rotation = node->geometry_transform.rotation;
  25092. ufbx_matrix geom_rot_mat = ufbx_transform_to_matrix(&geom_rot);
  25093. ufbx_matrix norm_mat = ufbx_matrix_mul(&node->node_to_world, &geom_rot_mat);
  25094. norm_mat = ufbx_matrix_for_normals(&norm_mat);
  25095. return norm_mat;
  25096. }
  25097. ufbx_abi ufbx_real ufbx_evaluate_curve(const ufbx_anim_curve *curve, double time, ufbx_real default_value)
  25098. {
  25099. if (!curve) return default_value;
  25100. if (curve->keyframes.count <= 1) {
  25101. if (curve->keyframes.count == 1) {
  25102. return curve->keyframes.data[0].value;
  25103. } else {
  25104. return default_value;
  25105. }
  25106. }
  25107. size_t begin = 0;
  25108. size_t end = curve->keyframes.count;
  25109. const ufbx_keyframe *keys = curve->keyframes.data;
  25110. while (end - begin >= 8) {
  25111. size_t mid = (begin + end) >> 1;
  25112. if (keys[mid].time <= time) {
  25113. begin = mid + 1;
  25114. } else {
  25115. end = mid;
  25116. }
  25117. }
  25118. end = curve->keyframes.count;
  25119. for (; begin < end; begin++) {
  25120. const ufbx_keyframe *next = &keys[begin];
  25121. if (next->time <= time) continue;
  25122. // First keyframe
  25123. if (begin == 0) return next->value;
  25124. const ufbx_keyframe *prev = next - 1;
  25125. // Exact keyframe
  25126. if (prev->time == time) return prev->value;
  25127. double rcp_delta = 1.0 / (next->time - prev->time);
  25128. double t = (time - prev->time) * rcp_delta;
  25129. switch (prev->interpolation) {
  25130. case UFBX_INTERPOLATION_CONSTANT_PREV:
  25131. return prev->value;
  25132. case UFBX_INTERPOLATION_CONSTANT_NEXT:
  25133. return next->value;
  25134. case UFBX_INTERPOLATION_LINEAR:
  25135. return (ufbx_real)(prev->value*(1.0 - t) + next->value*t);
  25136. case UFBX_INTERPOLATION_CUBIC:
  25137. {
  25138. double x1 = prev->right.dx * rcp_delta;
  25139. double x2 = 1.0 - next->left.dx * rcp_delta;
  25140. t = ufbxi_find_cubic_bezier_t(x1, x2, t);
  25141. double t2 = t*t, t3 = t2*t;
  25142. double u = 1.0 - t, u2 = u*u, u3 = u2*u;
  25143. double y0 = prev->value;
  25144. double y3 = next->value;
  25145. double y1 = y0 + prev->right.dy;
  25146. double y2 = y3 - next->left.dy;
  25147. return (ufbx_real)(u3*y0 + 3.0 * (u2*t*y1 + u*t2*y2) + t3*y3);
  25148. }
  25149. default:
  25150. ufbxi_unreachable("Bad interpolation mode");
  25151. return 0.0f;
  25152. }
  25153. }
  25154. // Last keyframe
  25155. return curve->keyframes.data[curve->keyframes.count - 1].value;
  25156. }
  25157. ufbx_abi ufbxi_noinline ufbx_real ufbx_evaluate_anim_value_real(const ufbx_anim_value *anim_value, double time)
  25158. {
  25159. if (!anim_value) {
  25160. return 0.0f;
  25161. }
  25162. ufbx_real res = anim_value->default_value.x;
  25163. if (anim_value->curves[0]) res = ufbx_evaluate_curve(anim_value->curves[0], time, res);
  25164. return res;
  25165. }
  25166. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_evaluate_anim_value_vec3(const ufbx_anim_value *anim_value, double time)
  25167. {
  25168. if (!anim_value) {
  25169. ufbx_vec3 zero = { 0.0f };
  25170. return zero;
  25171. }
  25172. ufbx_vec3 res = anim_value->default_value;
  25173. if (anim_value->curves[0]) res.x = ufbx_evaluate_curve(anim_value->curves[0], time, res.x);
  25174. if (anim_value->curves[1]) res.y = ufbx_evaluate_curve(anim_value->curves[1], time, res.y);
  25175. if (anim_value->curves[2]) res.z = ufbx_evaluate_curve(anim_value->curves[2], time, res.z);
  25176. return res;
  25177. }
  25178. ufbx_abi ufbxi_noinline ufbx_prop ufbx_evaluate_prop_len(const ufbx_anim *anim, const ufbx_element *element, const char *name, size_t name_len, double time)
  25179. {
  25180. ufbx_prop result;
  25181. ufbx_prop *prop = ufbx_find_prop_len(&element->props, name, name_len);
  25182. if (prop) {
  25183. result = *prop;
  25184. } else {
  25185. memset(&result, 0, sizeof(result));
  25186. result.name.data = name;
  25187. result.name.length = name_len;
  25188. result._internal_key = ufbxi_get_name_key(name, name_len);
  25189. result.flags = UFBX_PROP_FLAG_NOT_FOUND;
  25190. result.value_str.data = ufbxi_empty_char;
  25191. result.value_str.length = 0;
  25192. result.value_blob.data = NULL;
  25193. result.value_blob.size = 0;
  25194. }
  25195. if (anim->prop_overrides.count > 0) {
  25196. ufbxi_find_prop_override(&anim->prop_overrides, element->element_id, &result);
  25197. return result;
  25198. }
  25199. if ((result.flags & (UFBX_PROP_FLAG_ANIMATED|UFBX_PROP_FLAG_CONNECTED)) == 0) return result;
  25200. if ((prop->flags & UFBX_PROP_FLAG_CONNECTED) != 0 && !anim->ignore_connections) {
  25201. ufbxi_evaluate_connected_prop(&result, anim, element, prop->name.data, time);
  25202. }
  25203. ufbxi_evaluate_props(anim, element, time, &result, 1);
  25204. return result;
  25205. }
  25206. ufbx_abi ufbxi_noinline ufbx_props ufbx_evaluate_props(const ufbx_anim *anim, const ufbx_element *element, double time, ufbx_prop *buffer, size_t buffer_size)
  25207. {
  25208. ufbx_props ret = { NULL };
  25209. if (!element) return ret;
  25210. size_t num_anim = 0;
  25211. ufbxi_prop_iter iter; // ufbxi_uninit
  25212. ufbxi_init_prop_iter(&iter, anim, element);
  25213. const ufbx_prop *prop = NULL;
  25214. while ((prop = ufbxi_next_prop(&iter)) != NULL) {
  25215. if (!(prop->flags & (UFBX_PROP_FLAG_ANIMATED|UFBX_PROP_FLAG_OVERRIDDEN|UFBX_PROP_FLAG_CONNECTED))) continue;
  25216. if (num_anim >= buffer_size) break;
  25217. ufbx_prop *dst = &buffer[num_anim++];
  25218. *dst = *prop;
  25219. if ((prop->flags & UFBX_PROP_FLAG_CONNECTED) != 0 && !anim->ignore_connections) {
  25220. ufbxi_evaluate_connected_prop(dst, anim, element, prop->name.data, time);
  25221. }
  25222. }
  25223. ufbxi_evaluate_props(anim, element, time, buffer, num_anim);
  25224. ret.props.data = buffer;
  25225. ret.props.count = ret.num_animated = num_anim;
  25226. ret.defaults = (ufbx_props*)&element->props;
  25227. return ret;
  25228. }
  25229. ufbx_abi ufbxi_noinline ufbx_transform ufbx_evaluate_transform(const ufbx_anim *anim, const ufbx_node *node, double time)
  25230. {
  25231. return ufbx_evaluate_transform_flags(anim, node, time, 0);
  25232. }
  25233. static const char *const ufbxi_transform_props_all[] = {
  25234. ufbxi_Lcl_Rotation,
  25235. ufbxi_Lcl_Scaling,
  25236. ufbxi_Lcl_Translation,
  25237. ufbxi_PostRotation,
  25238. ufbxi_PreRotation,
  25239. ufbxi_RotationOffset,
  25240. ufbxi_RotationOrder,
  25241. ufbxi_RotationPivot,
  25242. ufbxi_ScalingOffset,
  25243. ufbxi_ScalingPivot,
  25244. };
  25245. static const char *const ufbxi_transform_props_rotation[] = {
  25246. ufbxi_Lcl_Rotation,
  25247. ufbxi_PostRotation,
  25248. ufbxi_PreRotation,
  25249. ufbxi_RotationOrder,
  25250. };
  25251. static const char *const ufbxi_transform_props_scale[] = {
  25252. ufbxi_Lcl_Scaling,
  25253. };
  25254. static const char *const ufbxi_transform_props_rotation_scale[] = {
  25255. ufbxi_Lcl_Rotation,
  25256. ufbxi_Lcl_Scaling,
  25257. ufbxi_PostRotation,
  25258. ufbxi_PreRotation,
  25259. ufbxi_RotationOrder,
  25260. };
  25261. ufbx_abi ufbxi_noinline ufbx_transform ufbx_evaluate_transform_flags(const ufbx_anim *anim, const ufbx_node *node, double time, uint32_t flags)
  25262. {
  25263. ufbx_assert(anim);
  25264. ufbx_assert(node);
  25265. if (!node) return ufbx_identity_transform;
  25266. if (!anim) return node->local_transform;
  25267. if (node->is_root) return node->local_transform;
  25268. if ((flags & UFBX_TRANSFORM_FLAG_EXPLICIT_INCLUDES) == 0) {
  25269. flags |= UFBX_TRANSFORM_FLAG_INCLUDE_ROTATION|UFBX_TRANSFORM_FLAG_INCLUDE_SCALE|UFBX_TRANSFORM_FLAG_INCLUDE_TRANSLATION;
  25270. }
  25271. const char *const *prop_names = ufbxi_transform_props_all;
  25272. size_t num_prop_names = ufbxi_arraycount(ufbxi_transform_props_all);
  25273. uint32_t components = flags & (UFBX_TRANSFORM_FLAG_INCLUDE_ROTATION|UFBX_TRANSFORM_FLAG_INCLUDE_SCALE|UFBX_TRANSFORM_FLAG_INCLUDE_TRANSLATION);
  25274. if (components == (UFBX_TRANSFORM_FLAG_INCLUDE_ROTATION|UFBX_TRANSFORM_FLAG_INCLUDE_SCALE)) {
  25275. prop_names = ufbxi_transform_props_rotation_scale;
  25276. num_prop_names = ufbxi_arraycount(ufbxi_transform_props_rotation_scale);
  25277. } else if (components == UFBX_TRANSFORM_FLAG_INCLUDE_ROTATION) {
  25278. prop_names = ufbxi_transform_props_rotation;
  25279. num_prop_names = ufbxi_arraycount(ufbxi_transform_props_rotation);
  25280. } else if (components == UFBX_TRANSFORM_FLAG_INCLUDE_SCALE) {
  25281. prop_names = ufbxi_transform_props_scale;
  25282. num_prop_names = ufbxi_arraycount(ufbxi_transform_props_scale);
  25283. } else if (components == 0) {
  25284. return ufbx_identity_transform;
  25285. }
  25286. const ufbx_vec3 *translation_scale = NULL;
  25287. ufbx_prop helper_scale; // ufbxi_uninit
  25288. ufbx_vec3 scale_factor = ufbxi_one_vec3;
  25289. bool use_scale_factor = false;
  25290. if (node->parent && (flags & (UFBX_TRANSFORM_FLAG_INCLUDE_SCALE|UFBX_TRANSFORM_FLAG_INCLUDE_TRANSLATION)) != 0) {
  25291. ufbx_node *parent = node->parent;
  25292. if ((flags & UFBX_TRANSFORM_FLAG_IGNORE_COMPONENTWISE_SCALE) == 0 && parent->inherit_scale_node) {
  25293. ufbx_node *p = parent->inherit_scale_node;
  25294. if (node->is_scale_helper) {
  25295. use_scale_factor = true;
  25296. }
  25297. while (p && p->scale_helper) {
  25298. ufbx_prop scale = ufbx_evaluate_prop(anim, &p->scale_helper->element, ufbxi_Lcl_Scaling, time);
  25299. scale_factor.x *= scale.value_vec3.x;
  25300. scale_factor.y *= scale.value_vec3.y;
  25301. scale_factor.z *= scale.value_vec3.z;
  25302. p = p->inherit_scale_node;
  25303. }
  25304. }
  25305. if (parent->scale_helper && (flags & UFBX_TRANSFORM_FLAG_IGNORE_SCALE_HELPER) == 0) {
  25306. helper_scale = ufbx_evaluate_prop(anim, &parent->scale_helper->element, ufbxi_Lcl_Scaling, time);
  25307. if (helper_scale.flags & UFBX_PROP_FLAG_NOT_FOUND) {
  25308. helper_scale.value_vec3.x = 1.0f;
  25309. helper_scale.value_vec3.y = 1.0f;
  25310. helper_scale.value_vec3.z = 1.0f;
  25311. }
  25312. helper_scale.value_vec3.x *= scale_factor.x;
  25313. helper_scale.value_vec3.y *= scale_factor.y;
  25314. helper_scale.value_vec3.z *= scale_factor.z;
  25315. translation_scale = &helper_scale.value_vec3;
  25316. }
  25317. }
  25318. ufbx_prop buf[ufbxi_arraycount(ufbxi_transform_props_all)]; // ufbxi_uninit
  25319. ufbx_props props = ufbxi_evaluate_selected_props(anim, &node->element, time, buf, prop_names, num_prop_names);
  25320. ufbx_rotation_order order = (ufbx_rotation_order)ufbxi_find_enum(&props, ufbxi_RotationOrder, UFBX_ROTATION_ORDER_XYZ, UFBX_ROTATION_ORDER_SPHERIC);
  25321. ufbx_transform transform; // ufbxi_uninit
  25322. if ((components & UFBX_TRANSFORM_FLAG_INCLUDE_TRANSLATION) != 0) {
  25323. transform = ufbxi_get_transform(&props, order, node, translation_scale);
  25324. } else {
  25325. transform.translation = ufbx_zero_vec3;
  25326. if ((components & UFBX_TRANSFORM_FLAG_INCLUDE_ROTATION) != 0) {
  25327. transform.rotation = ufbxi_get_rotation(&props, order, node);
  25328. } else {
  25329. transform.rotation = ufbx_identity_quat;
  25330. }
  25331. if ((components & UFBX_TRANSFORM_FLAG_INCLUDE_SCALE) != 0) {
  25332. transform.scale = ufbxi_get_scale(&props, node);
  25333. } else {
  25334. transform.scale = ufbxi_one_vec3;
  25335. }
  25336. }
  25337. if (use_scale_factor) {
  25338. transform.scale.x *= scale_factor.x;
  25339. transform.scale.y *= scale_factor.y;
  25340. transform.scale.z *= scale_factor.z;
  25341. }
  25342. return transform;
  25343. }
  25344. ufbx_abi ufbx_real ufbx_evaluate_blend_weight(const ufbx_anim *anim, const ufbx_blend_channel *channel, double time)
  25345. {
  25346. const char *prop_names[] = {
  25347. ufbxi_DeformPercent,
  25348. };
  25349. ufbx_prop buf[ufbxi_arraycount(prop_names)]; // ufbxi_uninit
  25350. ufbx_props props = ufbxi_evaluate_selected_props(anim, &channel->element, time, buf, prop_names, ufbxi_arraycount(prop_names));
  25351. return ufbxi_find_real(&props, ufbxi_DeformPercent, channel->weight * (ufbx_real)100.0) * (ufbx_real)0.01;
  25352. }
  25353. ufbx_abi ufbx_scene *ufbx_evaluate_scene(const ufbx_scene *scene, const ufbx_anim *anim, double time, const ufbx_evaluate_opts *opts, ufbx_error *error)
  25354. {
  25355. ufbxi_check_opts_ptr(ufbx_scene, opts, error);
  25356. #if UFBXI_FEATURE_SCENE_EVALUATION
  25357. ufbxi_eval_context ec = { 0 };
  25358. return ufbxi_evaluate_scene(&ec, (ufbx_scene*)scene, anim, time, opts, error);
  25359. #else
  25360. if (error) {
  25361. memset(error, 0, sizeof(ufbx_error));
  25362. ufbxi_fmt_err_info(error, "UFBX_ENABLE_SCENE_EVALUATION");
  25363. ufbxi_report_err_msg(error, "UFBXI_FEATURE_SCENE_EVALUATION", "Feature disabled");
  25364. }
  25365. return NULL;
  25366. #endif
  25367. }
  25368. ufbx_abi ufbx_anim *ufbx_create_anim(const ufbx_scene *scene, const ufbx_anim_opts *opts, ufbx_error *error)
  25369. {
  25370. ufbxi_check_opts_ptr(ufbx_anim, opts, error);
  25371. ufbx_assert(scene);
  25372. ufbxi_create_anim_context ac = { UFBX_ERROR_NONE };
  25373. if (opts) {
  25374. ac.opts = *opts;
  25375. }
  25376. ac.scene = scene;
  25377. int ok = ufbxi_create_anim_imp(&ac);
  25378. if (ok) {
  25379. ufbxi_clear_error(error);
  25380. ufbxi_anim_imp *imp = ac.imp;
  25381. return &imp->anim;
  25382. } else {
  25383. ufbxi_fix_error_type(&ac.error, "Failed to create anim");
  25384. if (error) *error = ac.error;
  25385. ufbxi_buf_free(&ac.result);
  25386. ufbxi_free_ator(&ac.ator_result);
  25387. return NULL;
  25388. }
  25389. }
  25390. ufbx_abi void ufbx_free_anim(ufbx_anim *anim)
  25391. {
  25392. if (!anim) return;
  25393. if (!anim->custom) return;
  25394. ufbxi_anim_imp *imp = ufbxi_get_imp(ufbxi_anim_imp, anim);
  25395. ufbx_assert(imp->magic == UFBXI_ANIM_IMP_MAGIC);
  25396. if (imp->magic != UFBXI_ANIM_IMP_MAGIC) return;
  25397. ufbxi_release_ref(&imp->refcount);
  25398. }
  25399. ufbx_abi void ufbx_retain_anim(ufbx_anim *anim)
  25400. {
  25401. if (!anim) return;
  25402. if (!anim->custom) return;
  25403. ufbxi_anim_imp *imp = ufbxi_get_imp(ufbxi_anim_imp, anim);
  25404. ufbx_assert(imp->magic == UFBXI_ANIM_IMP_MAGIC);
  25405. if (imp->magic != UFBXI_ANIM_IMP_MAGIC) return;
  25406. ufbxi_retain_ref(&imp->refcount);
  25407. }
  25408. ufbx_abi ufbx_baked_anim *ufbx_bake_anim(const ufbx_scene *scene, const ufbx_anim *anim, const ufbx_bake_opts *opts, ufbx_error *error)
  25409. {
  25410. ufbx_assert(scene);
  25411. #if UFBXI_FEATURE_ANIMATION_BAKING
  25412. ufbxi_check_opts_ptr(ufbx_baked_anim, opts, error);
  25413. if (!anim) {
  25414. anim = scene->anim;
  25415. }
  25416. ufbxi_bake_context bc = { UFBX_ERROR_NONE };
  25417. if (opts) {
  25418. bc.opts = *opts;
  25419. }
  25420. bc.scene = scene;
  25421. int ok = ufbxi_bake_anim_imp(&bc, anim);
  25422. ufbxi_buf_free(&bc.tmp);
  25423. ufbxi_buf_free(&bc.tmp_prop);
  25424. ufbxi_buf_free(&bc.tmp_times);
  25425. ufbxi_buf_free(&bc.tmp_bake_props);
  25426. ufbxi_buf_free(&bc.tmp_nodes);
  25427. ufbxi_buf_free(&bc.tmp_elements);
  25428. ufbxi_buf_free(&bc.tmp_props);
  25429. ufbxi_buf_free(&bc.tmp_bake_stack);
  25430. ufbxi_free_ator(&bc.ator_tmp);
  25431. if (ok) {
  25432. ufbxi_clear_error(error);
  25433. ufbxi_baked_anim_imp *imp = bc.imp;
  25434. return &imp->bake;
  25435. } else {
  25436. ufbxi_fix_error_type(&bc.error, "Failed to bake anim");
  25437. if (error) *error = bc.error;
  25438. ufbxi_buf_free(&bc.result);
  25439. ufbxi_free_ator(&bc.ator_result);
  25440. return NULL;
  25441. }
  25442. #else
  25443. if (error) {
  25444. memset(error, 0, sizeof(ufbx_error));
  25445. ufbxi_fmt_err_info(error, "UFBX_ENABLE_ANIMATION_BAKING");
  25446. ufbxi_report_err_msg(error, "UFBXI_FEATURE_ANIMATION_BAKING", "Feature disabled");
  25447. }
  25448. return NULL;
  25449. #endif
  25450. }
  25451. ufbx_abi void ufbx_retain_baked_anim(ufbx_baked_anim *bake)
  25452. {
  25453. if (!bake) return;
  25454. ufbxi_baked_anim_imp *imp = ufbxi_get_imp(ufbxi_baked_anim_imp, bake);
  25455. ufbx_assert(imp->magic == UFBXI_BAKED_ANIM_IMP_MAGIC);
  25456. if (imp->magic != UFBXI_BAKED_ANIM_IMP_MAGIC) return;
  25457. ufbxi_retain_ref(&imp->refcount);
  25458. }
  25459. ufbx_abi void ufbx_free_baked_anim(ufbx_baked_anim *bake)
  25460. {
  25461. if (!bake) return;
  25462. ufbxi_baked_anim_imp *imp = ufbxi_get_imp(ufbxi_baked_anim_imp, bake);
  25463. ufbx_assert(imp->magic == UFBXI_BAKED_ANIM_IMP_MAGIC);
  25464. if (imp->magic != UFBXI_BAKED_ANIM_IMP_MAGIC) return;
  25465. ufbxi_release_ref(&imp->refcount);
  25466. }
  25467. ufbx_abi ufbx_baked_node *ufbx_find_baked_node_by_typed_id(ufbx_baked_anim *bake, uint32_t typed_id)
  25468. {
  25469. size_t index = SIZE_MAX;
  25470. ufbxi_macro_lower_bound_eq(ufbx_baked_node, 8, &index, bake->nodes.data, 0, bake->nodes.count,
  25471. ( a->typed_id < typed_id ), ( a->typed_id == typed_id) );
  25472. return index < SIZE_MAX ? &bake->nodes.data[index] : NULL;
  25473. }
  25474. ufbx_abi ufbx_baked_node *ufbx_find_baked_node(ufbx_baked_anim *bake, ufbx_node *node)
  25475. {
  25476. if (!bake || !node) return NULL;
  25477. return ufbx_find_baked_node_by_typed_id(bake, node->typed_id);
  25478. }
  25479. ufbx_abi ufbx_baked_element *ufbx_find_baked_element_by_element_id(ufbx_baked_anim *bake, uint32_t element_id)
  25480. {
  25481. size_t index = SIZE_MAX;
  25482. ufbxi_macro_lower_bound_eq(ufbx_baked_element, 8, &index, bake->elements.data, 0, bake->elements.count,
  25483. ( a->element_id < element_id ), ( a->element_id == element_id) );
  25484. return index < SIZE_MAX ? &bake->elements.data[index] : NULL;
  25485. }
  25486. ufbx_abi ufbx_baked_element *ufbx_find_baked_element(ufbx_baked_anim *bake, ufbx_element *element)
  25487. {
  25488. if (!bake || !element) return NULL;
  25489. return ufbx_find_baked_element_by_element_id(bake, element->element_id);
  25490. }
  25491. ufbx_abi ufbx_vec3 ufbx_evaluate_baked_vec3(ufbx_baked_vec3_list keyframes, double time)
  25492. {
  25493. size_t begin = 0;
  25494. size_t end = keyframes.count;
  25495. const ufbx_baked_vec3 *keys = keyframes.data;
  25496. while (end - begin >= 8) {
  25497. size_t mid = (begin + end) >> 1;
  25498. if (keys[mid].time <= time) {
  25499. begin = mid + 1;
  25500. } else {
  25501. end = mid;
  25502. }
  25503. }
  25504. end = keyframes.count;
  25505. for (; begin < end; begin++) {
  25506. const ufbx_baked_vec3 *next = &keys[begin];
  25507. if (next->time <= time) continue;
  25508. if (begin == 0) return next->value;
  25509. const ufbx_baked_vec3 *prev = next - 1;
  25510. if (prev > keys && (prev->flags & UFBX_BAKED_KEY_STEP_RIGHT) != 0 && prev[-1].time == time) prev--;
  25511. if (time == prev->time) return prev->value;
  25512. double t = (time - prev->time) / (next->time - prev->time);
  25513. if (prev->flags & UFBX_BAKED_KEY_STEP_LEFT) t = 0.0;
  25514. if (next->flags & UFBX_BAKED_KEY_STEP_RIGHT) t = 1.0;
  25515. return ufbxi_lerp3(prev->value, next->value, (ufbx_real)t);
  25516. }
  25517. return keyframes.data[keyframes.count - 1].value;
  25518. }
  25519. ufbx_abi ufbx_quat ufbx_evaluate_baked_quat(ufbx_baked_quat_list keyframes, double time)
  25520. {
  25521. size_t begin = 0;
  25522. size_t end = keyframes.count;
  25523. const ufbx_baked_quat *keys = keyframes.data;
  25524. while (end - begin >= 8) {
  25525. size_t mid = (begin + end) >> 1;
  25526. if (keys[mid].time <= time) {
  25527. begin = mid + 1;
  25528. } else {
  25529. end = mid;
  25530. }
  25531. }
  25532. end = keyframes.count;
  25533. for (; begin < end; begin++) {
  25534. const ufbx_baked_quat *next = &keys[begin];
  25535. if (next->time <= time) continue;
  25536. if (begin == 0) return next->value;
  25537. const ufbx_baked_quat *prev = next - 1;
  25538. if (prev > keys && prev[-1].time == time) prev--;
  25539. if (time == prev->time) return prev->value;
  25540. double t = (time - prev->time) / (next->time - prev->time);
  25541. if (prev > keys && (prev->flags & UFBX_BAKED_KEY_STEP_RIGHT) != 0 && prev[-1].time == time) prev--;
  25542. if (prev->flags & UFBX_BAKED_KEY_STEP_LEFT) t = 0.0;
  25543. if (next->flags & UFBX_BAKED_KEY_STEP_RIGHT) t = 1.0;
  25544. return ufbx_quat_slerp(prev->value, next->value, (ufbx_real)t);
  25545. }
  25546. return keyframes.data[keyframes.count - 1].value;
  25547. }
  25548. ufbx_abi ufbx_bone_pose *ufbx_get_bone_pose(const ufbx_pose *pose, const ufbx_node *node)
  25549. {
  25550. if (!pose || !node) return NULL;
  25551. size_t index = SIZE_MAX;
  25552. ufbxi_macro_lower_bound_eq(ufbx_bone_pose, 8, &index, pose->bone_poses.data, 0, pose->bone_poses.count,
  25553. ( a->bone_node->typed_id < node->typed_id ), ( a->bone_node == node ));
  25554. return index < SIZE_MAX ? &pose->bone_poses.data[index] : NULL;
  25555. }
  25556. ufbx_abi ufbx_texture *ufbx_find_prop_texture_len(const ufbx_material *material, const char *name, size_t name_len)
  25557. {
  25558. ufbx_string name_str = ufbxi_safe_string(name, name_len);
  25559. if (!material) return NULL;
  25560. size_t index = SIZE_MAX;
  25561. ufbxi_macro_lower_bound_eq(ufbx_material_texture, 4, &index, material->textures.data, 0, material->textures.count,
  25562. ( ufbxi_str_less(a->material_prop, name_str) ), ( ufbxi_str_equal(a->material_prop, name_str) ));
  25563. return index < SIZE_MAX ? material->textures.data[index].texture : NULL;
  25564. }
  25565. ufbx_abi ufbx_string ufbx_find_shader_prop_len(const ufbx_shader *shader, const char *name, size_t name_len)
  25566. {
  25567. ufbx_shader_prop_binding_list bindings = ufbx_find_shader_prop_bindings_len(shader, name, name_len);
  25568. if (bindings.count > 0) {
  25569. return bindings.data[0].material_prop;
  25570. }
  25571. return ufbx_empty_string;
  25572. }
  25573. ufbx_abi ufbx_shader_prop_binding_list ufbx_find_shader_prop_bindings_len(const ufbx_shader *shader, const char *name, size_t name_len)
  25574. {
  25575. ufbx_shader_prop_binding_list bindings = { NULL, 0 };
  25576. ufbx_string name_str = ufbxi_safe_string(name, name_len);
  25577. if (!shader) return bindings;
  25578. ufbxi_for_ptr_list(ufbx_shader_binding, p_bind, shader->bindings) {
  25579. ufbx_shader_binding *bind = *p_bind;
  25580. size_t begin = SIZE_MAX;
  25581. ufbxi_macro_lower_bound_eq(ufbx_shader_prop_binding, 4, &begin, bind->prop_bindings.data, 0, bind->prop_bindings.count,
  25582. ( ufbxi_str_less(a->shader_prop, name_str) ), ( ufbxi_str_equal(a->shader_prop, name_str) ));
  25583. if (begin != SIZE_MAX) {
  25584. size_t end = begin;
  25585. ufbxi_macro_upper_bound_eq(ufbx_shader_prop_binding, 4, &end, bind->prop_bindings.data, begin, bind->prop_bindings.count,
  25586. ( ufbxi_str_equal(a->shader_prop, name_str) ));
  25587. bindings.data = bind->prop_bindings.data + begin;
  25588. bindings.count = end - begin;
  25589. break;
  25590. }
  25591. }
  25592. return bindings;
  25593. }
  25594. ufbx_abi ufbx_shader_texture_input *ufbx_find_shader_texture_input_len(const ufbx_shader_texture *shader, const char *name, size_t name_len)
  25595. {
  25596. ufbx_string name_str = ufbxi_safe_string(name, name_len);
  25597. size_t index = SIZE_MAX;
  25598. ufbxi_macro_lower_bound_eq(ufbx_shader_texture_input, 4, &index, shader->inputs.data, 0, shader->inputs.count,
  25599. ( ufbxi_str_less(a->name, name_str) ), ( ufbxi_str_equal(a->name, name_str) ));
  25600. if (index != SIZE_MAX) {
  25601. return &shader->inputs.data[index];
  25602. }
  25603. return NULL;
  25604. }
  25605. ufbx_abi bool ufbx_coordinate_axes_valid(ufbx_coordinate_axes axes)
  25606. {
  25607. if (axes.right < UFBX_COORDINATE_AXIS_POSITIVE_X || axes.right > UFBX_COORDINATE_AXIS_NEGATIVE_Z) return false;
  25608. if (axes.up < UFBX_COORDINATE_AXIS_POSITIVE_X || axes.up > UFBX_COORDINATE_AXIS_NEGATIVE_Z) return false;
  25609. if (axes.front < UFBX_COORDINATE_AXIS_POSITIVE_X || axes.front > UFBX_COORDINATE_AXIS_NEGATIVE_Z) return false;
  25610. // Check that all the positive/negative axes are used
  25611. uint32_t mask = 0;
  25612. mask |= 1u << ((uint32_t)axes.right >> 1);
  25613. mask |= 1u << ((uint32_t)axes.up >> 1);
  25614. mask |= 1u << ((uint32_t)axes.front >> 1);
  25615. return (mask & 0x7u) == 0x7u;
  25616. }
  25617. ufbx_abi ufbx_quat ufbx_quat_mul(ufbx_quat a, ufbx_quat b)
  25618. {
  25619. return ufbxi_mul_quat(a, b);
  25620. }
  25621. ufbx_abi ufbx_vec3 ufbx_vec3_normalize(ufbx_vec3 v)
  25622. {
  25623. return ufbxi_normalize3(v);
  25624. }
  25625. ufbx_abi ufbxi_noinline ufbx_real ufbx_quat_dot(ufbx_quat a, ufbx_quat b)
  25626. {
  25627. return a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
  25628. }
  25629. ufbx_abi ufbxi_noinline ufbx_quat ufbx_quat_normalize(ufbx_quat q)
  25630. {
  25631. ufbx_real norm = ufbx_quat_dot(q, q);
  25632. if (norm == 0.0) return ufbx_identity_quat;
  25633. norm = (ufbx_real)ufbx_sqrt(norm);
  25634. q.x /= norm;
  25635. q.y /= norm;
  25636. q.z /= norm;
  25637. q.w /= norm;
  25638. return q;
  25639. }
  25640. ufbx_abi ufbxi_noinline ufbx_quat ufbx_quat_fix_antipodal(ufbx_quat q, ufbx_quat reference)
  25641. {
  25642. if (ufbx_quat_dot(q, reference) < 0.0f) {
  25643. q.x = -q.x; q.y = -q.y; q.z = -q.z; q.w = -q.w;
  25644. }
  25645. return q;
  25646. }
  25647. ufbx_abi ufbxi_noinline ufbx_quat ufbx_quat_slerp(ufbx_quat a, ufbx_quat b, ufbx_real t)
  25648. {
  25649. double dot = a.x*b.x + a.y*b.y + a.z*b.z + a.w*b.w;
  25650. if (dot < 0.0) {
  25651. dot = -dot;
  25652. b.x = -b.x; b.y = -b.y; b.z = -b.z; b.w = -b.w;
  25653. }
  25654. double omega = ufbx_acos(ufbx_fmin(ufbx_fmax(dot, 0.0), 1.0));
  25655. if (omega <= 1.175494351e-38f) return a;
  25656. double rcp_so = 1.0 / ufbx_sin(omega);
  25657. double af = ufbx_sin((1.0 - t) * omega) * rcp_so;
  25658. double bf = ufbx_sin(t * omega) * rcp_so;
  25659. double x = af*a.x + bf*b.x;
  25660. double y = af*a.y + bf*b.y;
  25661. double z = af*a.z + bf*b.z;
  25662. double w = af*a.w + bf*b.w;
  25663. double rcp_len = 1.0 / ufbx_sqrt(x*x + y*y + z*z + w*w);
  25664. ufbx_quat ret;
  25665. ret.x = (ufbx_real)(x * rcp_len);
  25666. ret.y = (ufbx_real)(y * rcp_len);
  25667. ret.z = (ufbx_real)(z * rcp_len);
  25668. ret.w = (ufbx_real)(w * rcp_len);
  25669. return ret;
  25670. }
  25671. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_quat_rotate_vec3(ufbx_quat q, ufbx_vec3 v)
  25672. {
  25673. ufbx_real xy = q.x*v.y - q.y*v.x;
  25674. ufbx_real xz = q.x*v.z - q.z*v.x;
  25675. ufbx_real yz = q.y*v.z - q.z*v.y;
  25676. ufbx_vec3 r;
  25677. r.x = 2.0f * (+ q.w*yz + q.y*xy + q.z*xz) + v.x;
  25678. r.y = 2.0f * (- q.x*xy - q.w*xz + q.z*yz) + v.y;
  25679. r.z = 2.0f * (- q.x*xz - q.y*yz + q.w*xy) + v.z;
  25680. return r;
  25681. }
  25682. ufbx_abi ufbxi_noinline ufbx_quat ufbx_euler_to_quat(ufbx_vec3 v, ufbx_rotation_order order)
  25683. {
  25684. double vx = v.x * (UFBXI_DEG_TO_RAD_DOUBLE * 0.5);
  25685. double vy = v.y * (UFBXI_DEG_TO_RAD_DOUBLE * 0.5);
  25686. double vz = v.z * (UFBXI_DEG_TO_RAD_DOUBLE * 0.5);
  25687. double cx = ufbx_cos(vx), sx = ufbx_sin(vx);
  25688. double cy = ufbx_cos(vy), sy = ufbx_sin(vy);
  25689. double cz = ufbx_cos(vz), sz = ufbx_sin(vz);
  25690. ufbx_quat q;
  25691. // Generated by `misc/gen_rotation_order.py`
  25692. switch (order) {
  25693. case UFBX_ROTATION_ORDER_XYZ:
  25694. q.x = (ufbx_real)(-cx*sy*sz + cy*cz*sx);
  25695. q.y = (ufbx_real)(cx*cz*sy + cy*sx*sz);
  25696. q.z = (ufbx_real)(cx*cy*sz - cz*sx*sy);
  25697. q.w = (ufbx_real)(cx*cy*cz + sx*sy*sz);
  25698. break;
  25699. case UFBX_ROTATION_ORDER_XZY:
  25700. q.x = (ufbx_real)(cx*sy*sz + cy*cz*sx);
  25701. q.y = (ufbx_real)(cx*cz*sy + cy*sx*sz);
  25702. q.z = (ufbx_real)(cx*cy*sz - cz*sx*sy);
  25703. q.w = (ufbx_real)(cx*cy*cz - sx*sy*sz);
  25704. break;
  25705. case UFBX_ROTATION_ORDER_YZX:
  25706. q.x = (ufbx_real)(-cx*sy*sz + cy*cz*sx);
  25707. q.y = (ufbx_real)(cx*cz*sy - cy*sx*sz);
  25708. q.z = (ufbx_real)(cx*cy*sz + cz*sx*sy);
  25709. q.w = (ufbx_real)(cx*cy*cz + sx*sy*sz);
  25710. break;
  25711. case UFBX_ROTATION_ORDER_YXZ:
  25712. q.x = (ufbx_real)(-cx*sy*sz + cy*cz*sx);
  25713. q.y = (ufbx_real)(cx*cz*sy + cy*sx*sz);
  25714. q.z = (ufbx_real)(cx*cy*sz + cz*sx*sy);
  25715. q.w = (ufbx_real)(cx*cy*cz - sx*sy*sz);
  25716. break;
  25717. case UFBX_ROTATION_ORDER_ZXY:
  25718. q.x = (ufbx_real)(cx*sy*sz + cy*cz*sx);
  25719. q.y = (ufbx_real)(cx*cz*sy - cy*sx*sz);
  25720. q.z = (ufbx_real)(cx*cy*sz - cz*sx*sy);
  25721. q.w = (ufbx_real)(cx*cy*cz + sx*sy*sz);
  25722. break;
  25723. case UFBX_ROTATION_ORDER_ZYX:
  25724. q.x = (ufbx_real)(cx*sy*sz + cy*cz*sx);
  25725. q.y = (ufbx_real)(cx*cz*sy - cy*sx*sz);
  25726. q.z = (ufbx_real)(cx*cy*sz + cz*sx*sy);
  25727. q.w = (ufbx_real)(cx*cy*cz - sx*sy*sz);
  25728. break;
  25729. default:
  25730. q.x = q.y = q.z = 0.0f; q.w = 1.0f;
  25731. break;
  25732. }
  25733. return q;
  25734. }
  25735. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_quat_to_euler(ufbx_quat q, ufbx_rotation_order order)
  25736. {
  25737. // TODO: Derive these rigorously
  25738. #if defined(UFBX_REAL_IS_FLOAT)
  25739. const double eps = 0.9999999;
  25740. #else
  25741. const double eps = 0.999999999;
  25742. #endif
  25743. double vx, vy, vz;
  25744. double t;
  25745. double qx = q.x, qy = q.y, qz = q.z, qw = q.w;
  25746. // Generated by `misc/gen_quat_to_euler.py`
  25747. switch (order) {
  25748. case UFBX_ROTATION_ORDER_XYZ:
  25749. t = 2.0f*(qw*qy - qx*qz);
  25750. if (ufbx_fabs(t) < eps) {
  25751. vy = ufbx_asin(t);
  25752. vz = ufbx_atan2(2.0f*(qw*qz + qx*qy), 2.0f*(qw*qw + qx*qx) - 1.0f);
  25753. vx = -ufbx_atan2(-2.0f*(qw*qx + qy*qz), 2.0f*(qw*qw + qz*qz) - 1.0f);
  25754. } else {
  25755. vy = ufbx_copysign(UFBXI_DPI*0.5, t);
  25756. vz = ufbx_atan2(-2.0f*t*(qw*qx - qy*qz), t*(2.0f*qw*qy + 2.0f*qx*qz));
  25757. vx = 0.0f;
  25758. }
  25759. break;
  25760. case UFBX_ROTATION_ORDER_XZY:
  25761. t = 2.0f*(qw*qz + qx*qy);
  25762. if (ufbx_fabs(t) < eps) {
  25763. vz = ufbx_asin(t);
  25764. vy = ufbx_atan2(2.0f*(qw*qy - qx*qz), 2.0f*(qw*qw + qx*qx) - 1.0f);
  25765. vx = -ufbx_atan2(-2.0f*(qw*qx - qy*qz), 2.0f*(qw*qw + qy*qy) - 1.0f);
  25766. } else {
  25767. vz = ufbx_copysign(UFBXI_DPI*0.5, t);
  25768. vy = ufbx_atan2(2.0f*t*(qw*qx + qy*qz), -t*(2.0f*qx*qy - 2.0f*qw*qz));
  25769. vx = 0.0f;
  25770. }
  25771. break;
  25772. case UFBX_ROTATION_ORDER_YZX:
  25773. t = 2.0f*(qw*qz - qx*qy);
  25774. if (ufbx_fabs(t) < eps) {
  25775. vz = ufbx_asin(t);
  25776. vx = ufbx_atan2(2.0f*(qw*qx + qy*qz), 2.0f*(qw*qw + qy*qy) - 1.0f);
  25777. vy = -ufbx_atan2(-2.0f*(qw*qy + qx*qz), 2.0f*(qw*qw + qx*qx) - 1.0f);
  25778. } else {
  25779. vz = ufbx_copysign(UFBXI_DPI*0.5, t);
  25780. vx = ufbx_atan2(-2.0f*t*(qw*qy - qx*qz), t*(2.0f*qw*qz + 2.0f*qx*qy));
  25781. vy = 0.0f;
  25782. }
  25783. break;
  25784. case UFBX_ROTATION_ORDER_YXZ:
  25785. t = 2.0f*(qw*qx + qy*qz);
  25786. if (ufbx_fabs(t) < eps) {
  25787. vx = ufbx_asin(t);
  25788. vz = ufbx_atan2(2.0f*(qw*qz - qx*qy), 2.0f*(qw*qw + qy*qy) - 1.0f);
  25789. vy = -ufbx_atan2(-2.0f*(qw*qy - qx*qz), 2.0f*(qw*qw + qz*qz) - 1.0f);
  25790. } else {
  25791. vx = ufbx_copysign(UFBXI_DPI*0.5, t);
  25792. vz = ufbx_atan2(2.0f*t*(qw*qy + qx*qz), -t*(2.0f*qy*qz - 2.0f*qw*qx));
  25793. vy = 0.0f;
  25794. }
  25795. break;
  25796. case UFBX_ROTATION_ORDER_ZXY:
  25797. t = 2.0f*(qw*qx - qy*qz);
  25798. if (ufbx_fabs(t) < eps) {
  25799. vx = ufbx_asin(t);
  25800. vy = ufbx_atan2(2.0f*(qw*qy + qx*qz), 2.0f*(qw*qw + qz*qz) - 1.0f);
  25801. vz = -ufbx_atan2(-2.0f*(qw*qz + qx*qy), 2.0f*(qw*qw + qy*qy) - 1.0f);
  25802. } else {
  25803. vx = ufbx_copysign(UFBXI_DPI*0.5, t);
  25804. vy = ufbx_atan2(-2.0f*t*(qw*qz - qx*qy), t*(2.0f*qw*qx + 2.0f*qy*qz));
  25805. vz = 0.0f;
  25806. }
  25807. break;
  25808. case UFBX_ROTATION_ORDER_ZYX:
  25809. t = 2.0f*(qw*qy + qx*qz);
  25810. if (ufbx_fabs(t) < eps) {
  25811. vy = ufbx_asin(t);
  25812. vx = ufbx_atan2(2.0f*(qw*qx - qy*qz), 2.0f*(qw*qw + qz*qz) - 1.0f);
  25813. vz = -ufbx_atan2(-2.0f*(qw*qz - qx*qy), 2.0f*(qw*qw + qx*qx) - 1.0f);
  25814. } else {
  25815. vy = ufbx_copysign(UFBXI_DPI*0.5, t);
  25816. vx = ufbx_atan2(2.0f*t*(qw*qz + qx*qy), -t*(2.0f*qx*qz - 2.0f*qw*qy));
  25817. vz = 0.0f;
  25818. }
  25819. break;
  25820. default:
  25821. vx = vy = vz = 0.0;
  25822. break;
  25823. }
  25824. vx *= UFBXI_RAD_TO_DEG_DOUBLE;
  25825. vy *= UFBXI_RAD_TO_DEG_DOUBLE;
  25826. vz *= UFBXI_RAD_TO_DEG_DOUBLE;
  25827. ufbx_vec3 v = { (ufbx_real)vx, (ufbx_real)vy, (ufbx_real)vz };
  25828. return v;
  25829. }
  25830. ufbx_abi ufbxi_noinline ufbx_matrix ufbx_matrix_mul(const ufbx_matrix *a, const ufbx_matrix *b)
  25831. {
  25832. ufbx_assert(a && b);
  25833. if (!a || !b) return ufbx_identity_matrix;
  25834. ufbx_matrix dst;
  25835. dst.m03 = a->m00*b->m03 + a->m01*b->m13 + a->m02*b->m23 + a->m03;
  25836. dst.m13 = a->m10*b->m03 + a->m11*b->m13 + a->m12*b->m23 + a->m13;
  25837. dst.m23 = a->m20*b->m03 + a->m21*b->m13 + a->m22*b->m23 + a->m23;
  25838. dst.m00 = a->m00*b->m00 + a->m01*b->m10 + a->m02*b->m20;
  25839. dst.m10 = a->m10*b->m00 + a->m11*b->m10 + a->m12*b->m20;
  25840. dst.m20 = a->m20*b->m00 + a->m21*b->m10 + a->m22*b->m20;
  25841. dst.m01 = a->m00*b->m01 + a->m01*b->m11 + a->m02*b->m21;
  25842. dst.m11 = a->m10*b->m01 + a->m11*b->m11 + a->m12*b->m21;
  25843. dst.m21 = a->m20*b->m01 + a->m21*b->m11 + a->m22*b->m21;
  25844. dst.m02 = a->m00*b->m02 + a->m01*b->m12 + a->m02*b->m22;
  25845. dst.m12 = a->m10*b->m02 + a->m11*b->m12 + a->m12*b->m22;
  25846. dst.m22 = a->m20*b->m02 + a->m21*b->m12 + a->m22*b->m22;
  25847. return dst;
  25848. }
  25849. ufbx_abi ufbx_real ufbx_matrix_determinant(const ufbx_matrix *m)
  25850. {
  25851. return
  25852. - m->m02*m->m11*m->m20 + m->m01*m->m12*m->m20 + m->m02*m->m10*m->m21
  25853. - m->m00*m->m12*m->m21 - m->m01*m->m10*m->m22 + m->m00*m->m11*m->m22;
  25854. }
  25855. ufbx_abi ufbx_matrix ufbx_matrix_invert(const ufbx_matrix *m)
  25856. {
  25857. ufbx_real det = ufbx_matrix_determinant(m);
  25858. ufbx_matrix r;
  25859. if (ufbx_fabs(det) <= UFBX_EPSILON) {
  25860. memset(&r, 0, sizeof(r));
  25861. return r;
  25862. }
  25863. ufbx_real rcp_det = 1.0f / det;
  25864. r.m00 = ( - m->m12*m->m21 + m->m11*m->m22) * rcp_det;
  25865. r.m10 = ( + m->m12*m->m20 - m->m10*m->m22) * rcp_det;
  25866. r.m20 = ( - m->m11*m->m20 + m->m10*m->m21) * rcp_det;
  25867. r.m01 = ( + m->m02*m->m21 - m->m01*m->m22) * rcp_det;
  25868. r.m11 = ( - m->m02*m->m20 + m->m00*m->m22) * rcp_det;
  25869. r.m21 = ( + m->m01*m->m20 - m->m00*m->m21) * rcp_det;
  25870. r.m02 = ( - m->m02*m->m11 + m->m01*m->m12) * rcp_det;
  25871. r.m12 = ( + m->m02*m->m10 - m->m00*m->m12) * rcp_det;
  25872. r.m22 = ( - m->m01*m->m10 + m->m00*m->m11) * rcp_det;
  25873. r.m03 = (m->m03*m->m12*m->m21 - m->m02*m->m13*m->m21 - m->m03*m->m11*m->m22 + m->m01*m->m13*m->m22 + m->m02*m->m11*m->m23 - m->m01*m->m12*m->m23) * rcp_det;
  25874. r.m13 = (m->m02*m->m13*m->m20 - m->m03*m->m12*m->m20 + m->m03*m->m10*m->m22 - m->m00*m->m13*m->m22 - m->m02*m->m10*m->m23 + m->m00*m->m12*m->m23) * rcp_det;
  25875. r.m23 = (m->m03*m->m11*m->m20 - m->m01*m->m13*m->m20 - m->m03*m->m10*m->m21 + m->m00*m->m13*m->m21 + m->m01*m->m10*m->m23 - m->m00*m->m11*m->m23) * rcp_det;
  25876. return r;
  25877. }
  25878. ufbx_abi ufbxi_noinline ufbx_matrix ufbx_matrix_for_normals(const ufbx_matrix *m)
  25879. {
  25880. ufbx_real det = ufbx_matrix_determinant(m);
  25881. ufbx_real det_sign = det >= 0.0f ? 1.0f : -1.0f;
  25882. ufbx_matrix r;
  25883. r.m00 = ( - m->m12*m->m21 + m->m11*m->m22) * det_sign;
  25884. r.m01 = ( + m->m12*m->m20 - m->m10*m->m22) * det_sign;
  25885. r.m02 = ( - m->m11*m->m20 + m->m10*m->m21) * det_sign;
  25886. r.m10 = ( + m->m02*m->m21 - m->m01*m->m22) * det_sign;
  25887. r.m11 = ( - m->m02*m->m20 + m->m00*m->m22) * det_sign;
  25888. r.m12 = ( + m->m01*m->m20 - m->m00*m->m21) * det_sign;
  25889. r.m20 = ( - m->m02*m->m11 + m->m01*m->m12) * det_sign;
  25890. r.m21 = ( + m->m02*m->m10 - m->m00*m->m12) * det_sign;
  25891. r.m22 = ( - m->m01*m->m10 + m->m00*m->m11) * det_sign;
  25892. r.m03 = r.m13 = r.m23 = 0.0f;
  25893. return r;
  25894. }
  25895. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_transform_position(const ufbx_matrix *m, ufbx_vec3 v)
  25896. {
  25897. ufbx_assert(m);
  25898. if (!m) return ufbx_zero_vec3;
  25899. ufbx_vec3 r;
  25900. r.x = m->m00*v.x + m->m01*v.y + m->m02*v.z + m->m03;
  25901. r.y = m->m10*v.x + m->m11*v.y + m->m12*v.z + m->m13;
  25902. r.z = m->m20*v.x + m->m21*v.y + m->m22*v.z + m->m23;
  25903. return r;
  25904. }
  25905. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_transform_direction(const ufbx_matrix *m, ufbx_vec3 v)
  25906. {
  25907. ufbx_assert(m);
  25908. if (!m) return ufbx_zero_vec3;
  25909. ufbx_vec3 r;
  25910. r.x = m->m00*v.x + m->m01*v.y + m->m02*v.z;
  25911. r.y = m->m10*v.x + m->m11*v.y + m->m12*v.z;
  25912. r.z = m->m20*v.x + m->m21*v.y + m->m22*v.z;
  25913. return r;
  25914. }
  25915. ufbx_abi ufbxi_noinline ufbx_matrix ufbx_transform_to_matrix(const ufbx_transform *t)
  25916. {
  25917. ufbx_assert(t);
  25918. if (!t) return ufbx_identity_matrix;
  25919. ufbx_quat q = t->rotation;
  25920. ufbx_real sx = 2.0f * t->scale.x, sy = 2.0f * t->scale.y, sz = 2.0f * t->scale.z;
  25921. ufbx_real xx = q.x*q.x, xy = q.x*q.y, xz = q.x*q.z, xw = q.x*q.w;
  25922. ufbx_real yy = q.y*q.y, yz = q.y*q.z, yw = q.y*q.w;
  25923. ufbx_real zz = q.z*q.z, zw = q.z*q.w;
  25924. ufbx_matrix m;
  25925. m.m00 = sx * (- yy - zz + 0.5f);
  25926. m.m10 = sx * (+ xy + zw);
  25927. m.m20 = sx * (- yw + xz);
  25928. m.m01 = sy * (- zw + xy);
  25929. m.m11 = sy * (- xx - zz + 0.5f);
  25930. m.m21 = sy * (+ xw + yz);
  25931. m.m02 = sz * (+ xz + yw);
  25932. m.m12 = sz * (- xw + yz);
  25933. m.m22 = sz * (- xx - yy + 0.5f);
  25934. m.m03 = t->translation.x;
  25935. m.m13 = t->translation.y;
  25936. m.m23 = t->translation.z;
  25937. return m;
  25938. }
  25939. ufbx_abi ufbxi_noinline ufbx_transform ufbx_matrix_to_transform(const ufbx_matrix *m)
  25940. {
  25941. ufbx_assert(m);
  25942. if (!m) return ufbx_identity_transform;
  25943. ufbx_real det = ufbx_matrix_determinant(m);
  25944. ufbx_transform t;
  25945. t.translation = m->cols[3];
  25946. t.scale.x = ufbxi_length3(m->cols[0]);
  25947. t.scale.y = ufbxi_length3(m->cols[1]);
  25948. t.scale.z = ufbxi_length3(m->cols[2]);
  25949. // Flip a single non-zero axis if negative determinant
  25950. ufbx_real sign_x = 1.0f;
  25951. ufbx_real sign_y = 1.0f;
  25952. ufbx_real sign_z = 1.0f;
  25953. if (det < 0.0f) {
  25954. if (t.scale.x > 0.0f) sign_x = -1.0f;
  25955. else if (t.scale.y > 0.0f) sign_y = -1.0f;
  25956. else if (t.scale.z > 0.0f) sign_z = -1.0f;
  25957. }
  25958. ufbx_vec3 x = ufbxi_mul3(m->cols[0], t.scale.x > 0.0f ? sign_x / t.scale.x : 0.0f);
  25959. ufbx_vec3 y = ufbxi_mul3(m->cols[1], t.scale.y > 0.0f ? sign_y / t.scale.y : 0.0f);
  25960. ufbx_vec3 z = ufbxi_mul3(m->cols[2], t.scale.z > 0.0f ? sign_z / t.scale.z : 0.0f);
  25961. ufbx_real trace = x.x + y.y + z.z;
  25962. if (trace > 0.0f) {
  25963. ufbx_real a = (ufbx_real)ufbx_sqrt(ufbx_fmax(0.0, trace + 1.0)), b = (a != 0.0f) ? 0.5f / a : 0.0f;
  25964. t.rotation.x = (y.z - z.y) * b;
  25965. t.rotation.y = (z.x - x.z) * b;
  25966. t.rotation.z = (x.y - y.x) * b;
  25967. t.rotation.w = 0.5f * a;
  25968. } else if (x.x > y.y && x.x > z.z) {
  25969. ufbx_real a = (ufbx_real)ufbx_sqrt(ufbx_fmax(0.0, 1.0 + x.x - y.y - z.z)), b = (a != 0.0f) ? 0.5f / a : 0.0f;
  25970. t.rotation.x = 0.5f * a;
  25971. t.rotation.y = (y.x + x.y) * b;
  25972. t.rotation.z = (z.x + x.z) * b;
  25973. t.rotation.w = (y.z - z.y) * b;
  25974. }
  25975. else if (y.y > z.z) {
  25976. ufbx_real a = (ufbx_real)ufbx_sqrt(ufbx_fmax(0.0, 1.0 - x.x + y.y - z.z)), b = (a != 0.0f) ? 0.5f / a : 0.0f;
  25977. t.rotation.x = (y.x + x.y) * b;
  25978. t.rotation.y = 0.5f * a;
  25979. t.rotation.z = (z.y + y.z) * b;
  25980. t.rotation.w = (z.x - x.z) * b;
  25981. }
  25982. else {
  25983. ufbx_real a = (ufbx_real)ufbx_sqrt(ufbx_fmax(0.0, 1.0 - x.x - y.y + z.z)), b = (a != 0.0f) ? 0.5f / a : 0.0f;
  25984. t.rotation.x = (z.x + x.z) * b;
  25985. t.rotation.y = (z.y + y.z) * b;
  25986. t.rotation.z = 0.5f * a;
  25987. t.rotation.w = (x.y - y.x) * b;
  25988. }
  25989. ufbx_real len = t.rotation.x*t.rotation.x + t.rotation.y*t.rotation.y + t.rotation.z*t.rotation.z + t.rotation.w*t.rotation.w;
  25990. if (ufbx_fabs(len - 1.0f) > UFBX_EPSILON) {
  25991. if (ufbx_fabs(len) <= UFBX_EPSILON) {
  25992. t.rotation = ufbx_identity_quat;
  25993. } else {
  25994. t.rotation.x /= len;
  25995. t.rotation.y /= len;
  25996. t.rotation.z /= len;
  25997. t.rotation.w /= len;
  25998. }
  25999. }
  26000. t.scale.x *= sign_x;
  26001. t.scale.y *= sign_y;
  26002. t.scale.z *= sign_z;
  26003. return t;
  26004. }
  26005. ufbx_abi ufbxi_noinline ufbx_matrix ufbx_catch_get_skin_vertex_matrix(ufbx_panic *panic, const ufbx_skin_deformer *skin, size_t vertex, const ufbx_matrix *fallback)
  26006. {
  26007. ufbx_assert(skin);
  26008. if (ufbxi_panicf(panic, vertex < skin->vertices.count, "vertex (%zu) out of bounds (%zu)", vertex, skin->vertices.count)) return ufbx_identity_matrix;
  26009. if (!skin || vertex >= skin->vertices.count) return ufbx_identity_matrix;
  26010. ufbx_skin_vertex skin_vertex = skin->vertices.data[vertex];
  26011. ufbx_matrix mat = { 0.0f };
  26012. ufbx_quat q0 = { 0.0f }, qe = { 0.0f };
  26013. ufbx_quat first_q0 = { 0.0f };
  26014. ufbx_vec3 qs = { 0.0f, 0.0f, 0.0f };
  26015. ufbx_real total_weight = 0.0f;
  26016. for (uint32_t i = 0; i < skin_vertex.num_weights; i++) {
  26017. ufbx_skin_weight weight = skin->weights.data[skin_vertex.weight_begin + i];
  26018. ufbx_skin_cluster *cluster = skin->clusters.data[weight.cluster_index];
  26019. const ufbx_node *node = cluster->bone_node;
  26020. if (!node) continue;
  26021. total_weight += weight.weight;
  26022. if (skin_vertex.dq_weight > 0.0f) {
  26023. ufbx_transform t = cluster->geometry_to_world_transform;
  26024. ufbx_quat vq0 = t.rotation;
  26025. if (i == 0) first_q0 = vq0;
  26026. if (ufbx_quat_dot(first_q0, vq0) < 0.0f) {
  26027. vq0.x = -vq0.x;
  26028. vq0.y = -vq0.y;
  26029. vq0.z = -vq0.z;
  26030. vq0.w = -vq0.w;
  26031. }
  26032. ufbx_quat vqt = { 0.5f * t.translation.x, 0.5f * t.translation.y, 0.5f * t.translation.z };
  26033. ufbx_quat vqe = ufbxi_mul_quat(vqt, vq0);
  26034. ufbxi_add_weighted_quat(&q0, vq0, weight.weight);
  26035. ufbxi_add_weighted_quat(&qe, vqe, weight.weight);
  26036. ufbxi_add_weighted_vec3(&qs, t.scale, weight.weight);
  26037. }
  26038. if (skin_vertex.dq_weight < 1.0f) {
  26039. ufbxi_add_weighted_mat(&mat, &cluster->geometry_to_world, (1.0f-skin_vertex.dq_weight) * weight.weight);
  26040. }
  26041. }
  26042. if (total_weight <= 0.0f) {
  26043. if (fallback) {
  26044. return *fallback;
  26045. } else {
  26046. return ufbx_identity_matrix;
  26047. }
  26048. }
  26049. if (ufbx_fabs(total_weight - 1.0f) > UFBX_EPSILON) {
  26050. ufbx_real rcp_weight = ufbx_fabs(total_weight) > UFBX_EPSILON ? 1.0f / total_weight : 0.0f;
  26051. if (skin_vertex.dq_weight > 0.0f) {
  26052. q0.x *= rcp_weight; q0.y *= rcp_weight; q0.z *= rcp_weight; q0.w *= rcp_weight;
  26053. qe.x *= rcp_weight; qe.y *= rcp_weight; qe.z *= rcp_weight; qe.w *= rcp_weight;
  26054. qs.x *= rcp_weight; qs.y *= rcp_weight; qs.z *= rcp_weight;
  26055. }
  26056. if (skin_vertex.dq_weight < 1.0f) {
  26057. mat.m00 *= rcp_weight; mat.m01 *= rcp_weight; mat.m02 *= rcp_weight; mat.m03 *= rcp_weight;
  26058. mat.m10 *= rcp_weight; mat.m11 *= rcp_weight; mat.m12 *= rcp_weight; mat.m13 *= rcp_weight;
  26059. mat.m20 *= rcp_weight; mat.m21 *= rcp_weight; mat.m22 *= rcp_weight; mat.m23 *= rcp_weight;
  26060. }
  26061. }
  26062. if (skin_vertex.dq_weight > 0.0f) {
  26063. ufbx_transform dqt; // ufbxi_uninit
  26064. ufbx_real rcp_len = (ufbx_real)(1.0 / ufbx_sqrt(q0.x*q0.x + q0.y*q0.y + q0.z*q0.z + q0.w*q0.w));
  26065. ufbx_real rcp_len2x2 = 2.0f * rcp_len * rcp_len;
  26066. dqt.rotation.x = q0.x * rcp_len;
  26067. dqt.rotation.y = q0.y * rcp_len;
  26068. dqt.rotation.z = q0.z * rcp_len;
  26069. dqt.rotation.w = q0.w * rcp_len;
  26070. dqt.scale.x = qs.x;
  26071. dqt.scale.y = qs.y;
  26072. dqt.scale.z = qs.z;
  26073. dqt.translation.x = rcp_len2x2 * (- qe.w*q0.x + qe.x*q0.w - qe.y*q0.z + qe.z*q0.y);
  26074. dqt.translation.y = rcp_len2x2 * (- qe.w*q0.y + qe.x*q0.z + qe.y*q0.w - qe.z*q0.x);
  26075. dqt.translation.z = rcp_len2x2 * (- qe.w*q0.z - qe.x*q0.y + qe.y*q0.x + qe.z*q0.w);
  26076. ufbx_matrix dqm = ufbx_transform_to_matrix(&dqt);
  26077. if (skin_vertex.dq_weight < 1.0f) {
  26078. ufbxi_add_weighted_mat(&mat, &dqm, skin_vertex.dq_weight);
  26079. } else {
  26080. mat = dqm;
  26081. }
  26082. }
  26083. return mat;
  26084. }
  26085. ufbx_abi ufbxi_noinline uint32_t ufbx_get_blend_shape_offset_index(const ufbx_blend_shape *shape, size_t vertex)
  26086. {
  26087. ufbx_assert(shape);
  26088. if (!shape) return UFBX_NO_INDEX;
  26089. size_t index = SIZE_MAX;
  26090. uint32_t vertex_ix = (uint32_t)vertex;
  26091. ufbxi_macro_lower_bound_eq(uint32_t, 16, &index, shape->offset_vertices.data, 0, shape->num_offsets,
  26092. ( *a < vertex_ix ), ( *a == vertex_ix ));
  26093. if (index >= UINT32_MAX) return UFBX_NO_INDEX;
  26094. return (uint32_t)index;
  26095. }
  26096. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_get_blend_shape_vertex_offset(const ufbx_blend_shape *shape, size_t vertex)
  26097. {
  26098. uint32_t index = ufbx_get_blend_shape_offset_index(shape, vertex);
  26099. if (index == UFBX_NO_INDEX) return ufbx_zero_vec3;
  26100. return shape->position_offsets.data[index];
  26101. }
  26102. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_get_blend_vertex_offset(const ufbx_blend_deformer *blend, size_t vertex)
  26103. {
  26104. ufbx_assert(blend);
  26105. if (!blend) return ufbx_zero_vec3;
  26106. ufbx_vec3 offset = ufbx_zero_vec3;
  26107. ufbxi_for_ptr_list(ufbx_blend_channel, p_chan, blend->channels) {
  26108. ufbx_blend_channel *chan = *p_chan;
  26109. ufbxi_for_list(ufbx_blend_keyframe, key, chan->keyframes) {
  26110. if (key->effective_weight == 0.0f) continue;
  26111. ufbx_vec3 key_offset = ufbx_get_blend_shape_vertex_offset(key->shape, vertex);
  26112. ufbxi_add_weighted_vec3(&offset, key_offset, key->effective_weight);
  26113. }
  26114. }
  26115. return offset;
  26116. }
  26117. ufbx_abi void ufbx_add_blend_shape_vertex_offsets(const ufbx_blend_shape *shape, ufbx_vec3 *vertices, size_t num_vertices, ufbx_real weight)
  26118. {
  26119. if (weight == 0.0f) return;
  26120. if (!vertices) return;
  26121. size_t num_offsets = shape->num_offsets;
  26122. uint32_t *vertex_indices = shape->offset_vertices.data;
  26123. ufbx_vec3 *offsets = shape->position_offsets.data;
  26124. for (size_t i = 0; i < num_offsets; i++) {
  26125. uint32_t index = vertex_indices[i];
  26126. if (index < num_vertices) {
  26127. ufbxi_add_weighted_vec3(&vertices[index], offsets[i], weight);
  26128. }
  26129. }
  26130. }
  26131. ufbx_abi void ufbx_add_blend_vertex_offsets(const ufbx_blend_deformer *blend, ufbx_vec3 *vertices, size_t num_vertices, ufbx_real weight)
  26132. {
  26133. ufbx_assert(blend);
  26134. if (!blend) return;
  26135. ufbxi_for_ptr_list(ufbx_blend_channel, p_chan, blend->channels) {
  26136. ufbx_blend_channel *chan = *p_chan;
  26137. ufbxi_for_list(ufbx_blend_keyframe, key, chan->keyframes) {
  26138. if (key->effective_weight == 0.0f) continue;
  26139. ufbx_add_blend_shape_vertex_offsets(key->shape, vertices, num_vertices, weight * key->effective_weight);
  26140. }
  26141. }
  26142. }
  26143. ufbx_abi size_t ufbx_evaluate_nurbs_basis(const ufbx_nurbs_basis *basis, ufbx_real u, ufbx_real *weights, size_t num_weights, ufbx_real *derivatives, size_t num_derivatives)
  26144. {
  26145. ufbx_assert(basis);
  26146. if (!basis) return SIZE_MAX;
  26147. if (basis->order == 0) return SIZE_MAX;
  26148. if (!basis->valid) return SIZE_MAX;
  26149. size_t degree = basis->order - 1;
  26150. ufbx_assert(degree >= 1);
  26151. // Binary search for the knot span `[min_u, max_u]` where `min_u <= u < max_u`
  26152. ufbx_real_list knots = basis->knot_vector;
  26153. size_t knot = SIZE_MAX;
  26154. if (u <= basis->t_min) {
  26155. knot = degree;
  26156. u = basis->t_min;
  26157. } else if (u >= basis->t_max) {
  26158. knot = basis->knot_vector.count - degree - 2;
  26159. u = basis->t_max;
  26160. } else {
  26161. ufbxi_macro_lower_bound_eq(ufbx_real, 8, &knot, knots.data, 0, knots.count - 1,
  26162. ( a[1] <= u ), ( a[0] <= u && u < a[1] ));
  26163. }
  26164. // The found effective control points are found left from `knot`, locally
  26165. // we use `knot - ix` here as it's more convenient for the following algorithm
  26166. // but we return it as `knot - degree` so that users can find the control points
  26167. // at `points[knot], points[knot+1], ..., points[knot+degree]`
  26168. if (knot < degree) return SIZE_MAX;
  26169. if (num_derivatives == 0) derivatives = NULL;
  26170. if (num_weights < basis->order) return knot - degree;
  26171. if (!weights) return knot - degree;
  26172. weights[0] = 1.0f;
  26173. for (size_t p = 1; p <= degree; p++) {
  26174. ufbx_real prev = 0.0f;
  26175. ufbx_real g = 1.0f - ufbxi_nurbs_weight(&knots, knot - p + 1, p, u);
  26176. ufbx_real dg = 0.0f;
  26177. if (derivatives && p == degree) {
  26178. dg = ufbxi_nurbs_deriv(&knots, knot - p + 1, p);
  26179. }
  26180. for (size_t i = p; i > 0; i--) {
  26181. ufbx_real f = ufbxi_nurbs_weight(&knots, knot - p + i, p, u);
  26182. ufbx_real weight = weights[i - 1];
  26183. weights[i] = f*weight + g*prev;
  26184. if (derivatives && p == degree) {
  26185. ufbx_real df = ufbxi_nurbs_deriv(&knots, knot - p + i, p);
  26186. if (i < num_derivatives) {
  26187. derivatives[i] = df*weight - dg*prev;
  26188. }
  26189. dg = df;
  26190. }
  26191. prev = weight;
  26192. g = 1.0f - f;
  26193. }
  26194. weights[0] = g*prev;
  26195. if (derivatives && p == degree) {
  26196. derivatives[0] = -dg*prev;
  26197. }
  26198. }
  26199. return knot - degree;
  26200. }
  26201. ufbx_abi ufbxi_noinline ufbx_curve_point ufbx_evaluate_nurbs_curve(const ufbx_nurbs_curve *curve, ufbx_real u)
  26202. {
  26203. ufbx_curve_point result = { false };
  26204. ufbx_assert(curve);
  26205. if (!curve) return result;
  26206. ufbx_real weights[UFBXI_MAX_NURBS_ORDER]; // ufbxi_uninit
  26207. ufbx_real derivs[UFBXI_MAX_NURBS_ORDER]; // ufbxi_uninit
  26208. size_t base = ufbx_evaluate_nurbs_basis(&curve->basis, u, weights, UFBXI_MAX_NURBS_ORDER, derivs, UFBXI_MAX_NURBS_ORDER);
  26209. if (base == SIZE_MAX) return result;
  26210. ufbx_vec4 p = { 0 };
  26211. ufbx_vec4 d = { 0 };
  26212. size_t order = curve->basis.order;
  26213. if (order > UFBXI_MAX_NURBS_ORDER) return result;
  26214. if (curve->control_points.count == 0) return result;
  26215. for (size_t i = 0; i < order; i++) {
  26216. size_t ix = (base + i) % curve->control_points.count;
  26217. ufbx_vec4 cp = curve->control_points.data[ix];
  26218. ufbx_real weight = weights[i] * cp.w, deriv = derivs[i] * cp.w;
  26219. p.x += cp.x * weight;
  26220. p.y += cp.y * weight;
  26221. p.z += cp.z * weight;
  26222. p.w += weight;
  26223. d.x += cp.x * deriv;
  26224. d.y += cp.y * deriv;
  26225. d.z += cp.z * deriv;
  26226. d.w += deriv;
  26227. }
  26228. ufbx_real rcp_w = 1.0f / p.w;
  26229. result.valid = true;
  26230. result.position.x = p.x * rcp_w;
  26231. result.position.y = p.y * rcp_w;
  26232. result.position.z = p.z * rcp_w;
  26233. result.derivative.x = (d.x - d.w*result.position.x) * rcp_w;
  26234. result.derivative.y = (d.y - d.w*result.position.y) * rcp_w;
  26235. result.derivative.z = (d.z - d.w*result.position.z) * rcp_w;
  26236. return result;
  26237. }
  26238. ufbx_abi ufbxi_noinline ufbx_surface_point ufbx_evaluate_nurbs_surface(const ufbx_nurbs_surface *surface, ufbx_real u, ufbx_real v)
  26239. {
  26240. ufbx_surface_point result = { false };
  26241. ufbx_assert(surface);
  26242. if (!surface) return result;
  26243. ufbx_real weights_u[UFBXI_MAX_NURBS_ORDER], weights_v[UFBXI_MAX_NURBS_ORDER]; // ufbxi_uninit
  26244. ufbx_real derivs_u[UFBXI_MAX_NURBS_ORDER], derivs_v[UFBXI_MAX_NURBS_ORDER]; // ufbxi_uninit
  26245. size_t base_u = ufbx_evaluate_nurbs_basis(&surface->basis_u, u, weights_u, UFBXI_MAX_NURBS_ORDER, derivs_u, UFBXI_MAX_NURBS_ORDER);
  26246. size_t base_v = ufbx_evaluate_nurbs_basis(&surface->basis_v, v, weights_v, UFBXI_MAX_NURBS_ORDER, derivs_v, UFBXI_MAX_NURBS_ORDER);
  26247. if (base_u == SIZE_MAX || base_v == SIZE_MAX) return result;
  26248. ufbx_vec4 p = { 0 };
  26249. ufbx_vec4 du = { 0 };
  26250. ufbx_vec4 dv = { 0 };
  26251. size_t num_u = surface->num_control_points_u;
  26252. size_t num_v = surface->num_control_points_v;
  26253. size_t order_u = surface->basis_u.order;
  26254. size_t order_v = surface->basis_v.order;
  26255. if (order_u > UFBXI_MAX_NURBS_ORDER || order_v > UFBXI_MAX_NURBS_ORDER) return result;
  26256. if (num_u == 0 || num_v == 0) return result;
  26257. for (size_t vi = 0; vi < order_v; vi++) {
  26258. size_t vix = (base_v + vi) % num_v;
  26259. ufbx_real weight_v = weights_v[vi], deriv_v = derivs_v[vi];
  26260. for (size_t ui = 0; ui < order_u; ui++) {
  26261. size_t uix = (base_u + ui) % num_u;
  26262. ufbx_real weight_u = weights_u[ui], deriv_u = derivs_u[ui];
  26263. ufbx_vec4 cp = surface->control_points.data[vix * num_u + uix];
  26264. ufbx_real weight = weight_u * weight_v * cp.w;
  26265. ufbx_real wderiv_u = deriv_u * weight_v * cp.w;
  26266. ufbx_real wderiv_v = deriv_v * weight_u * cp.w;
  26267. p.x += cp.x * weight;
  26268. p.y += cp.y * weight;
  26269. p.z += cp.z * weight;
  26270. p.w += weight;
  26271. du.x += cp.x * wderiv_u;
  26272. du.y += cp.y * wderiv_u;
  26273. du.z += cp.z * wderiv_u;
  26274. du.w += wderiv_u;
  26275. dv.x += cp.x * wderiv_v;
  26276. dv.y += cp.y * wderiv_v;
  26277. dv.z += cp.z * wderiv_v;
  26278. dv.w += wderiv_v;
  26279. }
  26280. }
  26281. ufbx_real rcp_w = 1.0f / p.w;
  26282. result.valid = true;
  26283. result.position.x = p.x * rcp_w;
  26284. result.position.y = p.y * rcp_w;
  26285. result.position.z = p.z * rcp_w;
  26286. result.derivative_u.x = (du.x - du.w*result.position.x) * rcp_w;
  26287. result.derivative_u.y = (du.y - du.w*result.position.y) * rcp_w;
  26288. result.derivative_u.z = (du.z - du.w*result.position.z) * rcp_w;
  26289. result.derivative_v.x = (dv.x - dv.w*result.position.x) * rcp_w;
  26290. result.derivative_v.y = (dv.y - dv.w*result.position.y) * rcp_w;
  26291. result.derivative_v.z = (dv.z - dv.w*result.position.z) * rcp_w;
  26292. return result;
  26293. }
  26294. ufbx_abi ufbx_line_curve *ufbx_tessellate_nurbs_curve(const ufbx_nurbs_curve *curve, const ufbx_tessellate_curve_opts *opts, ufbx_error *error)
  26295. {
  26296. #if UFBXI_FEATURE_TESSELLATION
  26297. ufbxi_check_opts_ptr(ufbx_line_curve, opts, error);
  26298. ufbx_assert(curve);
  26299. if (!curve) return NULL;
  26300. ufbxi_tessellate_curve_context tc = { UFBX_ERROR_NONE };
  26301. if (opts) {
  26302. tc.opts = *opts;
  26303. }
  26304. tc.curve = curve;
  26305. int ok = ufbxi_tessellate_nurbs_curve_imp(&tc);
  26306. ufbxi_free_ator(&tc.ator_tmp);
  26307. if (ok) {
  26308. ufbxi_clear_error(error);
  26309. ufbxi_line_curve_imp *imp = tc.imp;
  26310. return &imp->curve;
  26311. } else {
  26312. ufbxi_fix_error_type(&tc.error, "Failed to tessellate");
  26313. if (error) *error = tc.error;
  26314. ufbxi_buf_free(&tc.result);
  26315. ufbxi_free_ator(&tc.ator_result);
  26316. return NULL;
  26317. }
  26318. #else
  26319. if (error) {
  26320. memset(error, 0, sizeof(ufbx_error));
  26321. ufbxi_fmt_err_info(error, "UFBX_ENABLE_TESSELLATION");
  26322. ufbxi_report_err_msg(error, "UFBXI_FEATURE_TESSELLATION", "Feature disabled");
  26323. }
  26324. return NULL;
  26325. #endif
  26326. }
  26327. ufbx_abi ufbx_mesh *ufbx_tessellate_nurbs_surface(const ufbx_nurbs_surface *surface, const ufbx_tessellate_surface_opts *opts, ufbx_error *error)
  26328. {
  26329. #if UFBXI_FEATURE_TESSELLATION
  26330. ufbx_assert(surface);
  26331. ufbxi_check_opts_ptr(ufbx_mesh, opts, error);
  26332. if (!surface) return NULL;
  26333. ufbxi_tessellate_surface_context tc = { UFBX_ERROR_NONE };
  26334. if (opts) {
  26335. tc.opts = *opts;
  26336. }
  26337. tc.surface = surface;
  26338. int ok = ufbxi_tessellate_nurbs_surface_imp(&tc);
  26339. ufbxi_buf_free(&tc.tmp);
  26340. ufbxi_map_free(&tc.position_map);
  26341. ufbxi_free_ator(&tc.ator_tmp);
  26342. if (ok) {
  26343. ufbxi_clear_error(error);
  26344. ufbxi_mesh_imp *imp = tc.imp;
  26345. return &imp->mesh;
  26346. } else {
  26347. ufbxi_fix_error_type(&tc.error, "Failed to tessellate");
  26348. if (error) *error = tc.error;
  26349. ufbxi_buf_free(&tc.result);
  26350. ufbxi_free_ator(&tc.ator_result);
  26351. return NULL;
  26352. }
  26353. #else
  26354. if (error) {
  26355. memset(error, 0, sizeof(ufbx_error));
  26356. ufbxi_report_err_msg(error, "UFBXI_FEATURE_TESSELLATION", "Feature disabled");
  26357. }
  26358. return NULL;
  26359. #endif
  26360. }
  26361. ufbx_abi void ufbx_free_line_curve(ufbx_line_curve *line_curve)
  26362. {
  26363. if (!line_curve) return;
  26364. if (!line_curve->from_tessellated_nurbs) return;
  26365. ufbxi_line_curve_imp *imp = ufbxi_get_imp(ufbxi_line_curve_imp, line_curve);
  26366. ufbx_assert(imp->magic == UFBXI_LINE_CURVE_IMP_MAGIC);
  26367. if (imp->magic != UFBXI_LINE_CURVE_IMP_MAGIC) return;
  26368. ufbxi_release_ref(&imp->refcount);
  26369. }
  26370. ufbx_abi void ufbx_retain_line_curve(ufbx_line_curve *line_curve)
  26371. {
  26372. if (!line_curve) return;
  26373. if (!line_curve->from_tessellated_nurbs) return;
  26374. ufbxi_line_curve_imp *imp = ufbxi_get_imp(ufbxi_line_curve_imp, line_curve);
  26375. ufbx_assert(imp->magic == UFBXI_LINE_CURVE_IMP_MAGIC);
  26376. if (imp->magic != UFBXI_LINE_CURVE_IMP_MAGIC) return;
  26377. ufbxi_retain_ref(&imp->refcount);
  26378. }
  26379. ufbx_abi uint32_t ufbx_find_face_index(ufbx_mesh *mesh, size_t index)
  26380. {
  26381. if (!mesh || index > UINT32_MAX) return UFBX_NO_INDEX;
  26382. uint32_t ix = (uint32_t)index;
  26383. size_t face_ix = SIZE_MAX;
  26384. ufbxi_macro_lower_bound_eq(ufbx_face, 4, &face_ix, mesh->faces.data, 0, mesh->faces.count,
  26385. ( a->index_begin + a->num_indices <= ix ), ( ix >= a->index_begin && ix < a->index_begin + a->num_indices ));
  26386. return (uint32_t)face_ix;
  26387. }
  26388. ufbx_abi ufbxi_noinline uint32_t ufbx_catch_triangulate_face(ufbx_panic *panic, uint32_t *indices, size_t num_indices, const ufbx_mesh *mesh, ufbx_face face)
  26389. {
  26390. #if UFBXI_FEATURE_TRIANGULATION
  26391. if (face.num_indices < 3) return 0;
  26392. size_t required_indices = ((size_t)face.num_indices - 2) * 3;
  26393. if (ufbxi_panicf(panic, num_indices >= required_indices, "Face needs at least %zu indices for triangles, got space for %zu", required_indices, num_indices)) return 0;
  26394. if (ufbxi_panicf(panic, face.index_begin < mesh->num_indices, "Face index begin (%u) out of bounds (%zu)", face.index_begin, mesh->num_indices)) return 0;
  26395. if (ufbxi_panicf(panic, mesh->num_indices - face.index_begin >= face.num_indices, "Face index end (%u + %u) out of bounds (%zu)", face.index_begin, face.num_indices, mesh->num_indices)) return 0;
  26396. if (face.num_indices == 3) {
  26397. // Fast case: Already a triangle
  26398. indices[0] = face.index_begin + 0;
  26399. indices[1] = face.index_begin + 1;
  26400. indices[2] = face.index_begin + 2;
  26401. return 1;
  26402. } else if (face.num_indices == 4) {
  26403. // Quad: Split along the shortest axis unless a vertex crosses the axis
  26404. uint32_t i0 = face.index_begin + 0;
  26405. uint32_t i1 = face.index_begin + 1;
  26406. uint32_t i2 = face.index_begin + 2;
  26407. uint32_t i3 = face.index_begin + 3;
  26408. ufbx_vec3 v0 = mesh->vertex_position.values.data[mesh->vertex_position.indices.data[i0]];
  26409. ufbx_vec3 v1 = mesh->vertex_position.values.data[mesh->vertex_position.indices.data[i1]];
  26410. ufbx_vec3 v2 = mesh->vertex_position.values.data[mesh->vertex_position.indices.data[i2]];
  26411. ufbx_vec3 v3 = mesh->vertex_position.values.data[mesh->vertex_position.indices.data[i3]];
  26412. ufbx_vec3 a = ufbxi_sub3(v2, v0);
  26413. ufbx_vec3 b = ufbxi_sub3(v3, v1);
  26414. ufbx_vec3 na1 = ufbxi_normalize3(ufbxi_cross3(a, ufbxi_sub3(v1, v0)));
  26415. ufbx_vec3 na3 = ufbxi_normalize3(ufbxi_cross3(a, ufbxi_sub3(v0, v3)));
  26416. ufbx_vec3 nb0 = ufbxi_normalize3(ufbxi_cross3(b, ufbxi_sub3(v1, v0)));
  26417. ufbx_vec3 nb2 = ufbxi_normalize3(ufbxi_cross3(b, ufbxi_sub3(v2, v1)));
  26418. ufbx_real dot_aa = ufbxi_dot3(a, a);
  26419. ufbx_real dot_bb = ufbxi_dot3(b, b);
  26420. ufbx_real dot_na = ufbxi_dot3(na1, na3);
  26421. ufbx_real dot_nb = ufbxi_dot3(nb0, nb2);
  26422. bool split_a = dot_aa <= dot_bb;
  26423. if (dot_na < 0.0f || dot_nb < 0.0f) {
  26424. split_a = dot_na >= dot_nb;
  26425. }
  26426. if (split_a) {
  26427. indices[0] = i0;
  26428. indices[1] = i1;
  26429. indices[2] = i2;
  26430. indices[3] = i2;
  26431. indices[4] = i3;
  26432. indices[5] = i0;
  26433. } else {
  26434. indices[0] = i1;
  26435. indices[1] = i2;
  26436. indices[2] = i3;
  26437. indices[3] = i3;
  26438. indices[4] = i0;
  26439. indices[5] = i1;
  26440. }
  26441. return 2;
  26442. } else {
  26443. ufbxi_ngon_context nc = { 0 };
  26444. nc.positions = mesh->vertex_position;
  26445. nc.face = face;
  26446. uint32_t num_indices_u32 = num_indices < UINT32_MAX ? (uint32_t)num_indices : UINT32_MAX;
  26447. uint32_t local_indices[12]; // ufbxi_uninit
  26448. if (num_indices_u32 < 12) {
  26449. uint32_t num_tris = ufbxi_triangulate_ngon(&nc, local_indices, 12);
  26450. memcpy(indices, local_indices, num_tris * 3 * sizeof(uint32_t));
  26451. return num_tris;
  26452. } else {
  26453. return ufbxi_triangulate_ngon(&nc, indices, num_indices_u32);
  26454. }
  26455. }
  26456. #else
  26457. ufbxi_panicf_imp(panic, "Triangulation disabled");
  26458. return 0;
  26459. #endif
  26460. }
  26461. ufbx_abi void ufbx_catch_compute_topology(ufbx_panic *panic, const ufbx_mesh *mesh, ufbx_topo_edge *indices, size_t num_indices)
  26462. {
  26463. if (ufbxi_panicf(panic, num_indices >= mesh->num_indices, "Required mesh.num_indices (%zu) indices, got %zu", mesh->num_indices, num_indices)) return;
  26464. ufbxi_compute_topology(mesh, indices);
  26465. }
  26466. ufbx_abi uint32_t ufbx_catch_topo_next_vertex_edge(ufbx_panic *panic, const ufbx_topo_edge *topo, size_t num_topo, uint32_t index)
  26467. {
  26468. if (index == UFBX_NO_INDEX) return UFBX_NO_INDEX;
  26469. if (ufbxi_panicf(panic, (size_t)index < num_topo, "index (%d) out of bounds (%zu)", index, num_topo)) return UFBX_NO_INDEX;
  26470. uint32_t twin = topo[index].twin;
  26471. if (twin == UFBX_NO_INDEX) return UFBX_NO_INDEX;
  26472. if (ufbxi_panicf(panic, (size_t)twin < num_topo, "Corrupted topology structure")) return UFBX_NO_INDEX;
  26473. return topo[twin].next;
  26474. }
  26475. ufbx_abi uint32_t ufbx_catch_topo_prev_vertex_edge(ufbx_panic *panic, const ufbx_topo_edge *topo, size_t num_topo, uint32_t index)
  26476. {
  26477. if (index == UFBX_NO_INDEX) return UFBX_NO_INDEX;
  26478. if (ufbxi_panicf(panic, (size_t)index < num_topo, "index (%d) out of bounds (%zu)", index, num_topo)) return UFBX_NO_INDEX;
  26479. return topo[topo[index].prev].twin;
  26480. }
  26481. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_catch_get_weighted_face_normal(ufbx_panic *panic, const ufbx_vertex_vec3 *positions, ufbx_face face)
  26482. {
  26483. if (ufbxi_panicf(panic, face.index_begin <= positions->indices.count, "Face index begin (%u) out of bounds (%zu)", face.index_begin, positions->indices.count)) return ufbx_zero_vec3;
  26484. if (ufbxi_panicf(panic, positions->indices.count - face.index_begin >= face.num_indices, "Face index end (%u + %u) out of bounds (%zu)", face.index_begin, face.num_indices, positions->indices.count)) return ufbx_zero_vec3;
  26485. if (face.num_indices < 3) {
  26486. return ufbx_zero_vec3;
  26487. } else if (face.num_indices == 3) {
  26488. ufbx_vec3 a = ufbx_get_vertex_vec3(positions, face.index_begin + 0);
  26489. ufbx_vec3 b = ufbx_get_vertex_vec3(positions, face.index_begin + 1);
  26490. ufbx_vec3 c = ufbx_get_vertex_vec3(positions, face.index_begin + 2);
  26491. return ufbxi_cross3(ufbxi_sub3(b, a), ufbxi_sub3(c, a));
  26492. } else if (face.num_indices == 4) {
  26493. ufbx_vec3 a = ufbx_get_vertex_vec3(positions, face.index_begin + 0);
  26494. ufbx_vec3 b = ufbx_get_vertex_vec3(positions, face.index_begin + 1);
  26495. ufbx_vec3 c = ufbx_get_vertex_vec3(positions, face.index_begin + 2);
  26496. ufbx_vec3 d = ufbx_get_vertex_vec3(positions, face.index_begin + 3);
  26497. return ufbxi_cross3(ufbxi_sub3(c, a), ufbxi_sub3(d, b));
  26498. } else {
  26499. // Newell's Method
  26500. ufbx_vec3 result = ufbx_zero_vec3;
  26501. for (size_t i = 0; i < face.num_indices; i++) {
  26502. size_t next = i + 1 < face.num_indices ? i + 1 : 0;
  26503. ufbx_vec3 a = ufbx_get_vertex_vec3(positions, face.index_begin + i);
  26504. ufbx_vec3 b = ufbx_get_vertex_vec3(positions, face.index_begin + next);
  26505. result.x += (a.y - b.y) * (a.z + b.z);
  26506. result.y += (a.z - b.z) * (a.x + b.x);
  26507. result.z += (a.x - b.x) * (a.y + b.y);
  26508. }
  26509. return result;
  26510. }
  26511. }
  26512. size_t ufbx_catch_generate_normal_mapping(ufbx_panic *panic, const ufbx_mesh *mesh, const ufbx_topo_edge *topo, size_t num_topo, uint32_t *normal_indices, size_t num_normal_indices, bool assume_smooth)
  26513. {
  26514. uint32_t next_index = 0;
  26515. if (ufbxi_panicf(panic, num_normal_indices >= mesh->num_indices, "Expected at least mesh.num_indices (%zu), got %zu", mesh->num_indices, num_normal_indices)) return 0;
  26516. for (size_t i = 0; i < mesh->num_indices; i++) {
  26517. normal_indices[i] = UFBX_NO_INDEX;
  26518. }
  26519. // Walk around vertices and merge around smooth edges
  26520. for (size_t vi = 0; vi < mesh->num_vertices; vi++) {
  26521. uint32_t original_start = mesh->vertex_first_index.data[vi];
  26522. if (original_start == UFBX_NO_INDEX) continue;
  26523. uint32_t start = original_start, cur = start;
  26524. for (;;) {
  26525. uint32_t prev = ufbx_topo_next_vertex_edge(topo, num_topo, cur);
  26526. if (!ufbxi_is_edge_smooth(mesh, topo, num_topo, cur, assume_smooth)) start = cur;
  26527. if (prev == UFBX_NO_INDEX) { start = cur; break; }
  26528. if (prev == original_start) break;
  26529. cur = prev;
  26530. }
  26531. normal_indices[start] = next_index++;
  26532. uint32_t next = start;
  26533. for (;;) {
  26534. next = ufbx_topo_prev_vertex_edge(topo, num_topo, next);
  26535. if (next == UFBX_NO_INDEX || next == start) break;
  26536. if (!ufbxi_is_edge_smooth(mesh, topo, num_topo, next, assume_smooth)) {
  26537. ++next_index;
  26538. }
  26539. normal_indices[next] = next_index - 1;
  26540. }
  26541. }
  26542. // Assign non-manifold indices
  26543. for (size_t i = 0; i < mesh->num_indices; i++) {
  26544. if (normal_indices[i] == UFBX_NO_INDEX) {
  26545. normal_indices[i] = next_index++;
  26546. }
  26547. }
  26548. return (size_t)next_index;
  26549. }
  26550. ufbx_abi size_t ufbx_generate_normal_mapping(const ufbx_mesh *mesh, const ufbx_topo_edge *topo, size_t num_topo, uint32_t *normal_indices, size_t num_normal_indices, bool assume_smooth)
  26551. {
  26552. return ufbx_catch_generate_normal_mapping(NULL, mesh, topo, num_topo, normal_indices, num_normal_indices, assume_smooth);
  26553. }
  26554. ufbx_abi void ufbx_catch_compute_normals(ufbx_panic *panic, const ufbx_mesh *mesh, const ufbx_vertex_vec3 *positions, const uint32_t *normal_indices, size_t num_normal_indices, ufbx_vec3 *normals, size_t num_normals)
  26555. {
  26556. if (ufbxi_panicf(panic, num_normal_indices >= mesh->num_indices, "Expected at least mesh.num_indices (%zu), got %zu", mesh->num_indices, num_normal_indices)) return;
  26557. memset(normals, 0, sizeof(ufbx_vec3)*num_normals);
  26558. for (size_t fi = 0; fi < mesh->num_faces; fi++) {
  26559. ufbx_face face = mesh->faces.data[fi];
  26560. ufbx_vec3 normal = ufbx_get_weighted_face_normal(positions, face);
  26561. for (size_t ix = 0; ix < face.num_indices; ix++) {
  26562. uint32_t index = normal_indices[face.index_begin + ix];
  26563. if (ufbxi_panicf(panic, index < num_normals, "Normal index (%d) out of bounds (%zu) at %zu", index, num_normals, ix)) return;
  26564. ufbx_vec3 *n = &normals[index];
  26565. *n = ufbxi_add3(*n, normal);
  26566. }
  26567. }
  26568. for (size_t i = 0; i < num_normals; i++) {
  26569. ufbx_real len = ufbxi_length3(normals[i]);
  26570. if (len > 0.0f) {
  26571. normals[i].x /= len;
  26572. normals[i].y /= len;
  26573. normals[i].z /= len;
  26574. }
  26575. }
  26576. }
  26577. ufbx_abi void ufbx_compute_normals(const ufbx_mesh *mesh, const ufbx_vertex_vec3 *positions, const uint32_t *normal_indices, size_t num_normal_indices, ufbx_vec3 *normals, size_t num_normals)
  26578. {
  26579. ufbx_catch_compute_normals(NULL, mesh, positions, normal_indices, num_normal_indices, normals, num_normals);
  26580. }
  26581. ufbx_abi ufbx_mesh *ufbx_subdivide_mesh(const ufbx_mesh *mesh, size_t level, const ufbx_subdivide_opts *opts, ufbx_error *error)
  26582. {
  26583. ufbxi_check_opts_ptr(ufbx_mesh, opts, error);
  26584. if (!mesh) return NULL;
  26585. if (level == 0) return (ufbx_mesh*)mesh;
  26586. return ufbxi_subdivide_mesh(mesh, level, opts, error);
  26587. }
  26588. ufbx_abi void ufbx_free_mesh(ufbx_mesh *mesh)
  26589. {
  26590. if (!mesh) return;
  26591. if (!mesh->subdivision_evaluated && !mesh->from_tessellated_nurbs) return;
  26592. ufbxi_mesh_imp *imp = ufbxi_get_imp(ufbxi_mesh_imp, mesh);
  26593. ufbx_assert(imp->magic == UFBXI_MESH_IMP_MAGIC);
  26594. if (imp->magic != UFBXI_MESH_IMP_MAGIC) return;
  26595. ufbxi_release_ref(&imp->refcount);
  26596. }
  26597. ufbx_abi void ufbx_retain_mesh(ufbx_mesh *mesh)
  26598. {
  26599. if (!mesh) return;
  26600. if (!mesh->subdivision_evaluated && !mesh->from_tessellated_nurbs) return;
  26601. ufbxi_mesh_imp *imp = ufbxi_get_imp(ufbxi_mesh_imp, mesh);
  26602. ufbx_assert(imp->magic == UFBXI_MESH_IMP_MAGIC);
  26603. if (imp->magic != UFBXI_MESH_IMP_MAGIC) return;
  26604. ufbxi_retain_ref(&imp->refcount);
  26605. }
  26606. ufbx_abi ufbx_geometry_cache *ufbx_load_geometry_cache(
  26607. const char *filename,
  26608. const ufbx_geometry_cache_opts *opts, ufbx_error *error)
  26609. {
  26610. return ufbx_load_geometry_cache_len(filename, strlen(filename),
  26611. opts, error);
  26612. }
  26613. ufbx_abi ufbx_geometry_cache *ufbx_load_geometry_cache_len(
  26614. const char *filename, size_t filename_len,
  26615. const ufbx_geometry_cache_opts *opts, ufbx_error *error)
  26616. {
  26617. ufbxi_check_opts_ptr(ufbx_geometry_cache, opts, error);
  26618. ufbx_string str = ufbxi_safe_string(filename, filename_len);
  26619. return ufbxi_load_geometry_cache(str, opts, error);
  26620. }
  26621. ufbx_abi void ufbx_free_geometry_cache(ufbx_geometry_cache *cache)
  26622. {
  26623. if (!cache) return;
  26624. ufbxi_geometry_cache_imp *imp = ufbxi_get_imp(ufbxi_geometry_cache_imp, cache);
  26625. ufbx_assert(imp->magic == UFBXI_CACHE_IMP_MAGIC);
  26626. if (imp->magic != UFBXI_CACHE_IMP_MAGIC) return;
  26627. if (imp->owned_by_scene) return;
  26628. ufbxi_release_ref(&imp->refcount);
  26629. }
  26630. ufbx_abi void ufbx_retain_geometry_cache(ufbx_geometry_cache *cache)
  26631. {
  26632. if (!cache) return;
  26633. ufbxi_geometry_cache_imp *imp = ufbxi_get_imp(ufbxi_geometry_cache_imp, cache);
  26634. ufbx_assert(imp->magic == UFBXI_CACHE_IMP_MAGIC);
  26635. if (imp->magic != UFBXI_CACHE_IMP_MAGIC) return;
  26636. if (imp->owned_by_scene) return;
  26637. ufbxi_retain_ref(&imp->refcount);
  26638. }
  26639. typedef struct {
  26640. union {
  26641. double f64[UFBXI_GEOMETRY_CACHE_BUFFER_SIZE];
  26642. float f32[UFBXI_GEOMETRY_CACHE_BUFFER_SIZE];
  26643. } src;
  26644. ufbx_real dst[UFBXI_GEOMETRY_CACHE_BUFFER_SIZE];
  26645. } ufbxi_geometry_cache_buffer;
  26646. ufbx_abi ufbxi_noinline size_t ufbx_read_geometry_cache_real(const ufbx_cache_frame *frame, ufbx_real *data, size_t count, const ufbx_geometry_cache_data_opts *user_opts)
  26647. {
  26648. #if UFBXI_FEATURE_GEOMETRY_CACHE
  26649. ufbxi_check_opts_return_no_error(0, user_opts);
  26650. if (!frame || count == 0) return 0;
  26651. ufbx_assert(data);
  26652. if (!data) return 0;
  26653. ufbx_geometry_cache_data_opts opts; // ufbxi_uninit
  26654. if (user_opts) {
  26655. opts = *user_opts;
  26656. } else {
  26657. memset(&opts, 0, sizeof(opts));
  26658. }
  26659. if (!opts.open_file_cb.fn) {
  26660. opts.open_file_cb.fn = ufbx_default_open_file;
  26661. }
  26662. bool use_double = false;
  26663. size_t src_count = 0;
  26664. switch (frame->data_format) {
  26665. case UFBX_CACHE_DATA_FORMAT_UNKNOWN: src_count = 0; break;
  26666. case UFBX_CACHE_DATA_FORMAT_REAL_FLOAT: src_count = frame->data_count; break;
  26667. case UFBX_CACHE_DATA_FORMAT_VEC3_FLOAT: src_count = frame->data_count * 3; break;
  26668. case UFBX_CACHE_DATA_FORMAT_REAL_DOUBLE: src_count = frame->data_count; use_double = true; break;
  26669. case UFBX_CACHE_DATA_FORMAT_VEC3_DOUBLE: src_count = frame->data_count * 3; use_double = true; break;
  26670. default: ufbxi_unreachable("Bad data_format"); break;
  26671. }
  26672. bool src_big_endian = false;
  26673. switch (frame->data_encoding) {
  26674. case UFBX_CACHE_DATA_ENCODING_UNKNOWN: return 0;
  26675. case UFBX_CACHE_DATA_ENCODING_LITTLE_ENDIAN: src_big_endian = false; break;
  26676. case UFBX_CACHE_DATA_ENCODING_BIG_ENDIAN: src_big_endian = true; break;
  26677. default: ufbxi_unreachable("Bad data_encoding"); break;
  26678. }
  26679. // Test endianness
  26680. bool dst_big_endian;
  26681. {
  26682. uint8_t buf[2];
  26683. uint16_t val = 0xbbaa;
  26684. memcpy(buf, &val, 2);
  26685. dst_big_endian = buf[0] == 0xbb;
  26686. }
  26687. if (src_count == 0) return 0;
  26688. src_count = ufbxi_min_sz(src_count, count);
  26689. ufbx_stream stream = { 0 };
  26690. if (!ufbxi_open_file(&opts.open_file_cb, &stream, frame->filename.data, frame->filename.length, NULL, NULL, UFBX_OPEN_FILE_GEOMETRY_CACHE)) {
  26691. return 0;
  26692. }
  26693. // Skip to the correct point in the file
  26694. uint64_t offset = frame->data_offset;
  26695. if (stream.skip_fn) {
  26696. while (offset > 0) {
  26697. size_t to_skip = (size_t)ufbxi_min64(offset, UFBXI_MAX_SKIP_SIZE);
  26698. if (!stream.skip_fn(stream.user, to_skip)) break;
  26699. offset -= to_skip;
  26700. }
  26701. } else {
  26702. char buffer[4096]; // ufbxi_uninit
  26703. while (offset > 0) {
  26704. size_t to_skip = (size_t)ufbxi_min64(offset, sizeof(buffer));
  26705. size_t num_read = stream.read_fn(stream.user, buffer, to_skip);
  26706. if (num_read != to_skip) break;
  26707. offset -= to_skip;
  26708. }
  26709. }
  26710. // Failed to skip all the way
  26711. if (offset > 0) {
  26712. if (stream.close_fn) {
  26713. stream.close_fn(stream.user);
  26714. }
  26715. return 0;
  26716. }
  26717. ufbx_real *dst = data;
  26718. size_t mirror_ix = (size_t)frame->mirror_axis - 1;
  26719. ufbxi_geometry_cache_buffer buffer; // ufbxi_uninit
  26720. while (src_count > 0) {
  26721. size_t to_read = ufbxi_min_sz(src_count, UFBXI_GEOMETRY_CACHE_BUFFER_SIZE);
  26722. src_count -= to_read;
  26723. size_t num_read = 0;
  26724. if (use_double) {
  26725. size_t bytes_read = stream.read_fn(stream.user, buffer.src.f64, to_read * sizeof(double));
  26726. if (bytes_read == SIZE_MAX) bytes_read = 0;
  26727. num_read = bytes_read / sizeof(double);
  26728. if (src_big_endian != dst_big_endian) {
  26729. for (size_t i = 0; i < num_read; i++) {
  26730. char t, *v = (char*)&buffer.src.f64[i];
  26731. t = v[0]; v[0] = v[7]; v[7] = t;
  26732. t = v[1]; v[1] = v[6]; v[6] = t;
  26733. t = v[2]; v[2] = v[5]; v[5] = t;
  26734. t = v[3]; v[3] = v[4]; v[4] = t;
  26735. }
  26736. }
  26737. ufbxi_nounroll for (size_t i = 0; i < num_read; i++) {
  26738. buffer.dst[i] = (ufbx_real)buffer.src.f64[i];
  26739. }
  26740. } else {
  26741. size_t bytes_read = stream.read_fn(stream.user, buffer.src.f32, to_read * sizeof(float));
  26742. if (bytes_read == SIZE_MAX) bytes_read = 0;
  26743. num_read = bytes_read / sizeof(float);
  26744. if (src_big_endian != dst_big_endian) {
  26745. for (size_t i = 0; i < num_read; i++) {
  26746. char t, *v = (char*)&buffer.src.f32[i];
  26747. t = v[0]; v[0] = v[3]; v[3] = t;
  26748. t = v[1]; v[1] = v[2]; v[2] = t;
  26749. }
  26750. }
  26751. ufbxi_nounroll for (size_t i = 0; i < num_read; i++) {
  26752. buffer.dst[i] = (ufbx_real)buffer.src.f32[i];
  26753. }
  26754. }
  26755. if (!opts.ignore_transform) {
  26756. ufbx_real scale = frame->scale_factor;
  26757. if (scale != 1.0f) {
  26758. for (size_t i = 0; i < num_read; i++) {
  26759. buffer.dst[i] *= scale;
  26760. }
  26761. }
  26762. if (frame->mirror_axis) {
  26763. while (mirror_ix < num_read) {
  26764. buffer.dst[mirror_ix] = -buffer.dst[mirror_ix];
  26765. mirror_ix += 3;
  26766. }
  26767. mirror_ix -= num_read;
  26768. }
  26769. }
  26770. if (dst) {
  26771. ufbx_real weight = opts.use_weight ? opts.weight : 1.0f;
  26772. if (opts.additive) {
  26773. ufbxi_nounroll for (size_t i = 0; i < num_read; i++) {
  26774. dst[i] += buffer.dst[i] * weight;
  26775. }
  26776. } else {
  26777. ufbxi_nounroll for (size_t i = 0; i < num_read; i++) {
  26778. dst[i] = buffer.dst[i] * weight;
  26779. }
  26780. }
  26781. dst += num_read;
  26782. }
  26783. if (num_read != to_read) break;
  26784. }
  26785. if (stream.close_fn) {
  26786. stream.close_fn(stream.user);
  26787. }
  26788. return ufbxi_to_size(dst - data);
  26789. #else
  26790. return 0;
  26791. #endif
  26792. }
  26793. ufbx_abi ufbxi_noinline size_t ufbx_sample_geometry_cache_real(const ufbx_cache_channel *channel, double time, ufbx_real *data, size_t count, const ufbx_geometry_cache_data_opts *user_opts)
  26794. {
  26795. #if UFBXI_FEATURE_GEOMETRY_CACHE
  26796. ufbxi_check_opts_return_no_error(0, user_opts);
  26797. if (!channel || count == 0) return 0;
  26798. ufbx_assert(data);
  26799. if (!data) return 0;
  26800. if (channel->frames.count == 0) return 0;
  26801. ufbx_geometry_cache_data_opts opts;
  26802. if (user_opts) {
  26803. opts = *user_opts;
  26804. } else {
  26805. memset(&opts, 0, sizeof(opts));
  26806. }
  26807. size_t begin = 0;
  26808. size_t end = channel->frames.count;
  26809. const ufbx_cache_frame *frames = channel->frames.data;
  26810. while (end - begin >= 8) {
  26811. size_t mid = (begin + end) >> 1;
  26812. if (frames[mid].time < time) {
  26813. begin = mid + 1;
  26814. } else {
  26815. end = mid;
  26816. }
  26817. }
  26818. const double eps = 0.00000001;
  26819. end = channel->frames.count;
  26820. for (; begin < end; begin++) {
  26821. const ufbx_cache_frame *next = &frames[begin];
  26822. if (next->time < time) continue;
  26823. // First keyframe
  26824. if (begin == 0) {
  26825. return ufbx_read_geometry_cache_real(next, data, count, &opts);
  26826. }
  26827. const ufbx_cache_frame *prev = next - 1;
  26828. // Snap to exact frames if near
  26829. if (ufbx_fabs(next->time - time) < eps) {
  26830. return ufbx_read_geometry_cache_real(next, data, count, &opts);
  26831. }
  26832. if (ufbx_fabs(prev->time - time) < eps) {
  26833. return ufbx_read_geometry_cache_real(prev, data, count, &opts);
  26834. }
  26835. double rcp_delta = 1.0 / (next->time - prev->time);
  26836. double t = (time - prev->time) * rcp_delta;
  26837. ufbx_real original_weight = opts.use_weight ? opts.weight : 1.0f;
  26838. opts.use_weight = true;
  26839. opts.weight = (ufbx_real)(original_weight * (1.0 - t));
  26840. size_t num_prev = ufbx_read_geometry_cache_real(prev, data, count, &opts);
  26841. opts.additive = true;
  26842. opts.weight = (ufbx_real)(original_weight * t);
  26843. return ufbx_read_geometry_cache_real(next, data, num_prev, &opts);
  26844. }
  26845. // Last frame
  26846. const ufbx_cache_frame *last = &frames[end - 1];
  26847. return ufbx_read_geometry_cache_real(last, data, count, &opts);
  26848. #else
  26849. return 0;
  26850. #endif
  26851. }
  26852. ufbx_abi ufbxi_noinline size_t ufbx_read_geometry_cache_vec3(const ufbx_cache_frame *frame, ufbx_vec3 *data, size_t count, const ufbx_geometry_cache_data_opts *opts)
  26853. {
  26854. #if UFBXI_FEATURE_GEOMETRY_CACHE
  26855. if (!frame || count == 0) return 0;
  26856. ufbx_assert(data);
  26857. if (!data) return 0;
  26858. return ufbx_read_geometry_cache_real(frame, (ufbx_real*)data, count * 3, opts) / 3;
  26859. #else
  26860. return 0;
  26861. #endif
  26862. }
  26863. ufbx_abi ufbxi_noinline size_t ufbx_sample_geometry_cache_vec3(const ufbx_cache_channel *channel, double time, ufbx_vec3 *data, size_t count, const ufbx_geometry_cache_data_opts *opts)
  26864. {
  26865. #if UFBXI_FEATURE_GEOMETRY_CACHE
  26866. if (!channel || count == 0) return 0;
  26867. ufbx_assert(data);
  26868. if (!data) return 0;
  26869. return ufbx_sample_geometry_cache_real(channel, time, (ufbx_real*)data, count * 3, opts) / 3;
  26870. #else
  26871. return 0;
  26872. #endif
  26873. }
  26874. ufbx_abi ufbx_dom_node *ufbx_dom_find_len(const ufbx_dom_node *parent, const char *name, size_t name_len)
  26875. {
  26876. ufbx_string ref = ufbxi_safe_string(name, name_len);
  26877. ufbxi_for_ptr_list(ufbx_dom_node, p_child, parent->children) {
  26878. if (ufbxi_str_equal((*p_child)->name, ref)) return (ufbx_dom_node*)*p_child;
  26879. }
  26880. return NULL;
  26881. }
  26882. ufbx_abi size_t ufbx_generate_indices(const ufbx_vertex_stream *streams, size_t num_streams, uint32_t *indices, size_t num_indices, const ufbx_allocator_opts *allocator, ufbx_error *error)
  26883. {
  26884. ufbx_error local_error; // ufbxi_uninit
  26885. if (!error) {
  26886. error = &local_error;
  26887. }
  26888. memset(error, 0, sizeof(ufbx_error));
  26889. return ufbxi_generate_indices(streams, num_streams, indices, num_indices, allocator, error);
  26890. }
  26891. ufbx_abi void ufbx_thread_pool_run_task(ufbx_thread_pool_context ctx, uint32_t index)
  26892. {
  26893. ufbxi_thread_pool_execute((ufbxi_thread_pool*)ctx, index);
  26894. }
  26895. ufbx_abi void ufbx_thread_pool_set_user_ptr(ufbx_thread_pool_context ctx, void *user)
  26896. {
  26897. ufbxi_thread_pool *pool = (ufbxi_thread_pool*)ctx;
  26898. pool->user_ptr = user;
  26899. }
  26900. ufbx_abi void *ufbx_thread_pool_get_user_ptr(ufbx_thread_pool_context ctx)
  26901. {
  26902. ufbxi_thread_pool *pool = (ufbxi_thread_pool*)ctx;
  26903. return pool->user_ptr;
  26904. }
  26905. ufbx_abi ufbxi_noinline ufbx_real ufbx_catch_get_vertex_real(ufbx_panic *panic, const ufbx_vertex_real *v, size_t index)
  26906. {
  26907. if (ufbxi_panicf(panic, index < v->indices.count, "index (%zu) out of range (%zu)", index, v->indices.count)) return 0.0f;
  26908. uint32_t ix = v->indices.data[index];
  26909. if (ufbxi_panicf(panic, (size_t)ix < v->values.count || ix == UFBX_NO_INDEX, "Corrupted or missing vertex attribute (%u) at %zu", ix, index)) return 0.0f;
  26910. return v->values.data[(int32_t)ix];
  26911. }
  26912. ufbx_abi ufbxi_noinline ufbx_vec2 ufbx_catch_get_vertex_vec2(ufbx_panic *panic, const ufbx_vertex_vec2 *v, size_t index)
  26913. {
  26914. if (ufbxi_panicf(panic, index < v->indices.count, "index (%zu) out of range (%zu)", index, v->indices.count)) return ufbx_zero_vec2;
  26915. uint32_t ix = v->indices.data[index];
  26916. if (ufbxi_panicf(panic, (size_t)ix < v->values.count || ix == UFBX_NO_INDEX, "Corrupted or missing vertex attribute (%u) at %zu", ix, index)) return ufbx_zero_vec2;
  26917. return v->values.data[(int32_t)ix];
  26918. }
  26919. ufbx_abi ufbxi_noinline ufbx_vec3 ufbx_catch_get_vertex_vec3(ufbx_panic *panic, const ufbx_vertex_vec3 *v, size_t index)
  26920. {
  26921. if (ufbxi_panicf(panic, index < v->indices.count, "index (%zu) out of range (%zu)", index, v->indices.count)) return ufbx_zero_vec3;
  26922. uint32_t ix = v->indices.data[index];
  26923. if (ufbxi_panicf(panic, (size_t)ix < v->values.count || ix == UFBX_NO_INDEX, "Corrupted or missing vertex attribute (%u) at %zu", ix, index)) return ufbx_zero_vec3;
  26924. return v->values.data[(int32_t)ix];
  26925. }
  26926. ufbx_abi ufbxi_noinline ufbx_vec4 ufbx_catch_get_vertex_vec4(ufbx_panic *panic, const ufbx_vertex_vec4 *v, size_t index)
  26927. {
  26928. if (ufbxi_panicf(panic, index < v->indices.count, "index (%zu) out of range (%zu)", index, v->indices.count)) return ufbx_zero_vec4;
  26929. uint32_t ix = v->indices.data[index];
  26930. if (ufbxi_panicf(panic, (size_t)ix < v->values.count || ix == UFBX_NO_INDEX, "Corrupted or missing vertex attribute (%u) at %zu", ix, index)) return ufbx_zero_vec4;
  26931. return v->values.data[(int32_t)ix];
  26932. }
  26933. ufbx_abi ufbx_real ufbx_catch_get_vertex_w_vec3(ufbx_panic *panic, const ufbx_vertex_vec3 *v, size_t index)
  26934. {
  26935. if (ufbxi_panicf(panic, index < v->indices.count, "index (%zu) out of range (%zu)", index, v->indices.count)) return 0.0f;
  26936. if (v->values_w.count == 0) return 0.0f;
  26937. uint32_t ix = v->indices.data[index];
  26938. if (ufbxi_panicf(panic, (size_t)ix < v->values.count || ix == UFBX_NO_INDEX, "Corrupted or missing vertex attribute (%u) at %zu", ix, index)) return 0.0f;
  26939. return v->values_w.data[(int32_t)ix];
  26940. }
  26941. ufbx_abi ufbx_unknown *ufbx_as_unknown(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_UNKNOWN ? (ufbx_unknown*)element : NULL; }
  26942. ufbx_abi ufbx_node *ufbx_as_node(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_NODE ? (ufbx_node*)element : NULL; }
  26943. ufbx_abi ufbx_mesh *ufbx_as_mesh(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_MESH ? (ufbx_mesh*)element : NULL; }
  26944. ufbx_abi ufbx_light *ufbx_as_light(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_LIGHT ? (ufbx_light*)element : NULL; }
  26945. ufbx_abi ufbx_camera *ufbx_as_camera(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_CAMERA ? (ufbx_camera*)element : NULL; }
  26946. ufbx_abi ufbx_bone *ufbx_as_bone(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_BONE ? (ufbx_bone*)element : NULL; }
  26947. ufbx_abi ufbx_empty *ufbx_as_empty(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_EMPTY ? (ufbx_empty*)element : NULL; }
  26948. ufbx_abi ufbx_line_curve *ufbx_as_line_curve(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_LINE_CURVE ? (ufbx_line_curve*)element : NULL; }
  26949. ufbx_abi ufbx_nurbs_curve *ufbx_as_nurbs_curve(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_NURBS_CURVE ? (ufbx_nurbs_curve*)element : NULL; }
  26950. ufbx_abi ufbx_nurbs_surface *ufbx_as_nurbs_surface(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_NURBS_SURFACE ? (ufbx_nurbs_surface*)element : NULL; }
  26951. ufbx_abi ufbx_nurbs_trim_surface *ufbx_as_nurbs_trim_surface(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_NURBS_TRIM_SURFACE ? (ufbx_nurbs_trim_surface*)element : NULL; }
  26952. ufbx_abi ufbx_nurbs_trim_boundary *ufbx_as_nurbs_trim_boundary(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_NURBS_TRIM_BOUNDARY ? (ufbx_nurbs_trim_boundary*)element : NULL; }
  26953. ufbx_abi ufbx_procedural_geometry *ufbx_as_procedural_geometry(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_PROCEDURAL_GEOMETRY ? (ufbx_procedural_geometry*)element : NULL; }
  26954. ufbx_abi ufbx_stereo_camera *ufbx_as_stereo_camera(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_STEREO_CAMERA ? (ufbx_stereo_camera*)element : NULL; }
  26955. ufbx_abi ufbx_camera_switcher *ufbx_as_camera_switcher(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_CAMERA_SWITCHER ? (ufbx_camera_switcher*)element : NULL; }
  26956. ufbx_abi ufbx_marker *ufbx_as_marker(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_MARKER ? (ufbx_marker*)element : NULL; }
  26957. ufbx_abi ufbx_lod_group *ufbx_as_lod_group(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_LOD_GROUP ? (ufbx_lod_group*)element : NULL; }
  26958. ufbx_abi ufbx_skin_deformer *ufbx_as_skin_deformer(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_SKIN_DEFORMER ? (ufbx_skin_deformer*)element : NULL; }
  26959. ufbx_abi ufbx_skin_cluster *ufbx_as_skin_cluster(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_SKIN_CLUSTER ? (ufbx_skin_cluster*)element : NULL; }
  26960. ufbx_abi ufbx_blend_deformer *ufbx_as_blend_deformer(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_BLEND_DEFORMER ? (ufbx_blend_deformer*)element : NULL; }
  26961. ufbx_abi ufbx_blend_channel *ufbx_as_blend_channel(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_BLEND_CHANNEL ? (ufbx_blend_channel*)element : NULL; }
  26962. ufbx_abi ufbx_blend_shape *ufbx_as_blend_shape(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_BLEND_SHAPE ? (ufbx_blend_shape*)element : NULL; }
  26963. ufbx_abi ufbx_cache_deformer *ufbx_as_cache_deformer(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_CACHE_DEFORMER ? (ufbx_cache_deformer*)element : NULL; }
  26964. ufbx_abi ufbx_cache_file *ufbx_as_cache_file(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_CACHE_FILE ? (ufbx_cache_file*)element : NULL; }
  26965. ufbx_abi ufbx_material *ufbx_as_material(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_MATERIAL ? (ufbx_material*)element : NULL; }
  26966. ufbx_abi ufbx_texture *ufbx_as_texture(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_TEXTURE ? (ufbx_texture*)element : NULL; }
  26967. ufbx_abi ufbx_video *ufbx_as_video(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_VIDEO ? (ufbx_video*)element : NULL; }
  26968. ufbx_abi ufbx_shader *ufbx_as_shader(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_SHADER ? (ufbx_shader*)element : NULL; }
  26969. ufbx_abi ufbx_shader_binding *ufbx_as_shader_binding(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_SHADER_BINDING ? (ufbx_shader_binding*)element : NULL; }
  26970. ufbx_abi ufbx_anim_stack *ufbx_as_anim_stack(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_ANIM_STACK ? (ufbx_anim_stack*)element : NULL; }
  26971. ufbx_abi ufbx_anim_layer *ufbx_as_anim_layer(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_ANIM_LAYER ? (ufbx_anim_layer*)element : NULL; }
  26972. ufbx_abi ufbx_anim_value *ufbx_as_anim_value(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_ANIM_VALUE ? (ufbx_anim_value*)element : NULL; }
  26973. ufbx_abi ufbx_anim_curve *ufbx_as_anim_curve(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_ANIM_CURVE ? (ufbx_anim_curve*)element : NULL; }
  26974. ufbx_abi ufbx_display_layer *ufbx_as_display_layer(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_DISPLAY_LAYER ? (ufbx_display_layer*)element : NULL; }
  26975. ufbx_abi ufbx_selection_set *ufbx_as_selection_set(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_SELECTION_SET ? (ufbx_selection_set*)element : NULL; }
  26976. ufbx_abi ufbx_selection_node *ufbx_as_selection_node(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_SELECTION_NODE ? (ufbx_selection_node*)element : NULL; }
  26977. ufbx_abi ufbx_character *ufbx_as_character(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_CHARACTER ? (ufbx_character*)element : NULL; }
  26978. ufbx_abi ufbx_constraint *ufbx_as_constraint(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_CONSTRAINT ? (ufbx_constraint*)element : NULL; }
  26979. ufbx_abi ufbx_audio_layer *ufbx_as_audio_layer(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_AUDIO_LAYER ? (ufbx_audio_layer*)element : NULL; }
  26980. ufbx_abi ufbx_audio_clip *ufbx_as_audio_clip(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_AUDIO_CLIP ? (ufbx_audio_clip*)element : NULL; }
  26981. ufbx_abi ufbx_pose *ufbx_as_pose(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_POSE ? (ufbx_pose*)element : NULL; }
  26982. ufbx_abi ufbx_metadata_object *ufbx_as_metadata_object(const ufbx_element *element) { return element && element->type == UFBX_ELEMENT_METADATA_OBJECT ? (ufbx_metadata_object*)element : NULL; }
  26983. #ifdef __cplusplus
  26984. }
  26985. #endif
  26986. #endif
  26987. #if defined(_MSC_VER)
  26988. #pragma warning(pop)
  26989. #elif defined(__clang__)
  26990. #pragma clang diagnostic pop
  26991. #elif defined(__GNUC__)
  26992. #pragma GCC diagnostic pop
  26993. #endif