12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578 |
- /*
- * apck.h - Asset Pack (unpacker)
- * https://gitlab.com/bztsrc/assetpack
- *
- * Copyright (C) 2024 bzt, MIT license
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
- * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
- * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * @brief Asset Pack single header library
- */
- #ifndef APCK_H
- #define APCK_H
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include <stdint.h>
- #include <stdlib.h>
- #include <string.h>
- #define APCK_MAGIC "APCK"
- #ifdef _MSC_VER
- #pragma pack(push)
- #pragma pack(1)
- #define _PACK
- #else
- #define _PACK __attribute__((packed))
- #endif
- typedef struct {
- uint8_t magic[4];
- uint32_t hdr_size;
- uint8_t engine[12];
- uint32_t version;
- uint32_t size;
- uint32_t chksum;
- uint8_t enckey[32];
- } _PACK apck_hdr_t;
- #ifdef _MSC_VER
- #pragma pack(pop)
- #endif
- #undef _PACK
- #ifndef DBG
- #define DBG(a)
- #endif
- #ifndef __THROW
- #define __THROW
- #endif
- int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen);
- uint8_t *stbi_load_from_memory(uint8_t const *buffer, int len, int *x, int *y, int *comp, int req_comp);
- int stb_vorbis_decode_memory(const uint8_t *mem, int len, int *channels, int *sample_rate, short **output);
- enum { APCK_OK, APCK_ERR_BADINP, APCK_ERR_BADPCK, APCK_ERR_NOMEM };
- enum { APCK_LOCALE, APCK_FONT = 32, APCK_BGM, APCK_SFX, APCK_VIDEO, APCK_MODEL, APCK_IMAGE, APCK_ATLAS, APCK_SPRITE, APCK_MAP,
- APCK_OBJECT = 46, APCK_SCRIPT, APCK_DATA01, APCK_DATA02, APCK_DATA03, APCK_DATA04, APCK_DATA05, APCK_DATA06, APCK_DATA07,
- APCK_DATA08, APCK_DATA09, APCK_DATA10, APCK_DATA11, APCK_DATA12, APCK_DATA13, APCK_DATA14, APCK_DATA15, APCK_DATA16,
- APCK_NUMTYPES };
- enum { APCK_REGULAR = 0, APCK_BOLD = 1, APCK_ITALIC = 2, APCK_UNDERLINE = 16, APCK_STRIKETHROUGH = 32 };
- #define APCK_COMPRESSED(c,i) (((c) < APCK_FONT && !(i)) || (c) == APCK_FONT || ((c) >= APCK_SPRITE && (c) <= APCK_SCRIPT))
- typedef void* (*apck_initcb_t)(uint8_t *enckey);
- typedef int (*apck_readcb_t)(void *enc, uint64_t offs, uint8_t *buf, uint64_t size);
- typedef struct {
- void *f;
- uint64_t size;
- uint8_t *str;
- uint32_t aidx;
- void *enc;
- } apck_archive_t;
- typedef struct {
- int archive, w, h;
- char *name;
- uint32_t str;
- uint64_t offs;
- uint64_t size;
- uint64_t comp;
- uint8_t *buf;
- } apck_file_t;
- typedef struct {
- char engine[16];
- uint32_t version;
- uint32_t numarchive;
- uint32_t numfiles[APCK_NUMTYPES];
- apck_initcb_t initcb;
- apck_readcb_t readcb;
- apck_archive_t *archives;
- apck_file_t *files[APCK_NUMTYPES];
- uint32_t locale, *msgstr[APCK_FONT];
- void *font;
- } apck_t;
- uint8_t *apck_uleb128(uint8_t *ptr, uint64_t *value);
- uint32_t apck_crc32(uint8_t *buf, uint32_t size);
- int apck_init(apck_t *ctx, char *engine, uint32_t version, apck_initcb_t initcb, apck_readcb_t readcb);
- uint8_t *apck_readbuf(apck_t *ctx, uint32_t archive, uint64_t offs, uint64_t size);
- uint64_t apck_read(apck_t *ctx, uint32_t archive, uint64_t offs, uint8_t *buf, uint64_t size);
- int apck_load(apck_t *ctx, char *fn);
- int apck_free(apck_t *ctx);
- int apck_release(apck_t *ctx, int type, char *name);
- apck_file_t *apck_lookup(apck_t *ctx, int type, char *name);
- uint8_t *apck_asset(apck_t *ctx, int type, char *name, uint64_t *size);
- uint32_t *apck_image(apck_t *ctx, int type, char *name, int *w, int *h);
- int16_t *apck_audio(apck_t *ctx, int type, char *name, int *numsamples, int *channels);
- int apck_font(apck_t *ctx, char *name);
- uint32_t *apck_text(apck_t *ctx, char *msgid, uint32_t color, int fontstyle, int fontsize, int *w, int *h);
- /**************** embeded apck_file.h ****************/
- #ifndef APCK_FILE_H
- #define APCK_FILE_H
- #ifdef __WIN32__
- #include <windows.h>
- #include <winnls.h>
- #include <fileapi.h>
- #include <wchar.h>
- void apck_utf8_ucs2(char *fn, wchar_t *szFn);
- #else
- #include <unistd.h>
- #endif
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <limits.h>
- #ifndef PATH_MAX
- #define PATH_MAX 4096
- #endif
- #ifndef FILENAME_MAX
- #define FILENAME_MAX 255
- #endif
- void *apck_fileopen(char *fn, uint64_t *size);
- void *apck_fileopenw(char *fn);
- uint64_t apck_filewrite(void *f, void *buf, uint64_t size);
- uint64_t apck_fileread(void *f, void *buf, uint64_t size);
- void apck_fileseek(void *f, uint64_t offs);
- void apck_fileclose(void *f);
- #ifdef APCK_IMPLEMENTATION
- #ifdef __WIN32__
- void apck_utf8_ucs2(char *fn, wchar_t *szFn)
- {
- int i;
- memset(szFn, 0, 2*(PATH_MAX + FILENAME_MAX + 1));
- MultiByteToWideChar(CP_UTF8, 0, fn, -1, szFn, PATH_MAX + FILENAME_MAX);
- for(i = 0; szFn[i]; i++) if(szFn[i] == L'/') szFn[i] = L'\\';
- }
- #endif
- void *apck_fileopen(char *fn, uint64_t *size)
- {
- #ifdef __WIN32__
- struct _stat64 st;
- static wchar_t szFn[PATH_MAX + FILENAME_MAX + 1];
- HANDLE f;
- if(size) *size = 0;
- if(!fn || !*fn) return NULL;
- apck_utf8_ucs2(fn, (wchar_t*)szFn);
- if(_wstat64(szFn, &st) || !S_ISREG(st.st_mode)) return NULL;
- f = CreateFileW(szFn, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
- if(f == INVALID_HANDLE_VALUE) f = NULL;
- #else
- struct stat st;
- FILE *f;
- if(size) *size = 0;
- if(!fn || !*fn || (size && (stat(fn, &st) || !S_ISREG(st.st_mode)))) return NULL;
- f = fopen(fn, "rb");
- #endif
- if(size) *size = (uint64_t)st.st_size;
- return (void*)f;
- }
- void *apck_fileopenw(char *fn)
- {
- #ifdef __WIN32__
- wchar_t szFn[PATH_MAX + FILENAME_MAX + 1];
- HANDLE f;
- if(!fn || !*fn) return NULL;
- apck_utf8_ucs2(fn, szFn);
- f = CreateFileW(szFn, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
- if(f == INVALID_HANDLE_VALUE) f = NULL;
- #else
- FILE *f;
- if(!fn || !*fn) return NULL;
- f = fopen(fn, "wb");
- #endif
- return (void*)f;
- }
- uint64_t apck_filewrite(void *f, void *buf, uint64_t size)
- {
- #ifdef __WIN32__
- DWORD t;
- if(!f || !buf || !size) return 0;
- if(!WriteFile((HANDLE)f, buf, (DWORD)size, &t, NULL)) t = 0;
- return (uint64_t)t;
- #else
- if(!f || !buf || !size) return 0;
- return (uint64_t)fwrite(buf, 1, size, (FILE*)f);
- #endif
- }
- uint64_t apck_fileread(void *f, void *buf, uint64_t size)
- {
- #ifdef __WIN32__
- DWORD t;
- if(!f || !buf || !size) return 0;
- if(!ReadFile((HANDLE)f, buf, (DWORD)size, &t, NULL)) t = 0;
- return (uint64_t)t;
- #else
- if(!f || !buf || !size) return 0;
- return (uint64_t)fread(buf, 1, (size_t)size, (FILE*)f);
- #endif
- }
- void apck_fileseek(void *f, uint64_t offs)
- {
- #ifdef __WIN32__
- LARGE_INTEGER pos;
- pos.QuadPart = offs;
- SetFilePointerEx((HANDLE)f, pos, NULL, FILE_BEGIN);
- #else
- fseek((FILE*)f, offs, SEEK_SET);
- #endif
- }
- void apck_fileclose(void *f)
- {
- if(f) {
- #ifdef __WIN32__
- CloseHandle((HANDLE)f);
- #else
- fclose((FILE*)f);
- #endif
- }
- }
- #endif
- #endif
- /**************** embeded apck_map.h ****************/
- #ifndef APCK_MAP_H
- #define APCK_MAP_H
- enum { APCK_ORTHOGONAL = 'o', APCK_ISOMETRIC = 'i', APCK_VERTHEX = 'v', APCK_HORIZHEX = 'h' };
- typedef struct {
- uint8_t *v;
- uint32_t x, y;
- } apck_map_list_t;
- typedef struct {
- int type, disptype;
- int offX, offY;
- int parX, parY;
- int movX, movY;
- uint32_t size;
- uint8_t *data;
- } apck_map_layer_t;
- typedef struct {
- int type, tilew, tileh, w, h, l, proplen;
- uint8_t *properties;
- apck_map_layer_t *layers;
- } apck_map_t;
- apck_map_t *apck_map_new(int type, int tilew, int tileh, int w, int h, int proplen, uint8_t *properties);
- apck_map_layer_t *apck_map_layer(apck_map_t *map, int type, uint32_t datasize, void *data);
- int apck_map_free(apck_map_t *map);
- apck_map_t *apck_map_decode(uint8_t *str, uint8_t *buf, uint64_t size);
- #ifdef APCK_IMPLEMENTATION
- apck_map_t *apck_map_new(int type, int tilew, int tileh, int w, int h, int proplen, uint8_t *properties)
- {
- apck_map_t *ret;
- if(tilew < 1 || tileh < 1 || w < 1 || h < 1 || !(ret = (apck_map_t*)malloc(sizeof(apck_map_t))))
- return NULL;
- memset(ret, 0, sizeof(apck_map_t));
- ret->type = type;
- ret->tilew = tilew;
- ret->tileh = tileh;
- ret->w = w;
- ret->h = h;
- if(proplen && properties && (ret->properties = (uint8_t*)malloc(proplen))) {
- ret->proplen = proplen;
- memcpy(ret->properties, properties, proplen);
- }
- return ret;
- }
- apck_map_layer_t *apck_map_layer(apck_map_t *map, int type, uint32_t datasize, void *data)
- {
- int i;
- uint32_t l = 0;
- if(!map) return NULL;
- if(type == APCK_SPRITE) l = datasize * sizeof(apck_map_list_t); else
- if(type == APCK_MAP) l = map->w * map->h * sizeof(uint32_t); else {
- if(!data) return NULL;
- if(type >= APCK_OBJECT) l = datasize;
- else l = strlen((char*)data) + 1;
- }
- i = map->l++;
- if(!(map->layers = (apck_map_layer_t*)realloc(map->layers, map->l * sizeof(apck_map_layer_t)))) {
- map->l = 0;
- return NULL;
- }
- memset(&map->layers[i], 0, sizeof(apck_map_layer_t));
- map->layers[i].type = type;
- map->layers[i].parX = map->layers[i].parY = map->layers[i].movX = map->layers[i].movY = 100;
- if(l) {
- if(!(map->layers[i].data = (uint8_t*)malloc(l))) {
- map->l--;
- return NULL;
- }
- memset(map->layers[i].data, 0, l);
- map->layers[i].size = l;
- if(type != APCK_MAP && type != APCK_SPRITE && data)
- memcpy(map->layers[i].data, data, l);
- }
- return &map->layers[i];
- }
- int apck_map_free(apck_map_t *map)
- {
- int i;
- if(!map) return APCK_ERR_BADINP;
- if(map->layers) {
- for(i = 0; i < map->l; i++)
- if(map->layers[i].data)
- free(map->layers[i].data);
- free(map->layers);
- }
- if(map->properties)
- free(map->properties);
- free(map);
- return APCK_OK;
- }
- apck_map_t *apck_map_decode(uint8_t *str, uint8_t *buf, uint64_t size)
- {
- apck_map_t *map = NULL;
- apck_map_layer_t *layer;
- apck_map_list_t *list;
- uint64_t i, j, k, n, s, tw, th, w, h, l, parX, parY, offX, offY, movX, movY, type, disptype;
- uint32_t *data;
- uint8_t *ptr = buf + 4;
- if(!str || !buf || !size || memcmp(buf, "MAP", 3)) return NULL;
- ptr = apck_uleb128(ptr, &tw);
- ptr = apck_uleb128(ptr, &th);
- ptr = apck_uleb128(ptr, &w);
- ptr = apck_uleb128(ptr, &h);
- ptr = apck_uleb128(ptr, &l);
- ptr = apck_uleb128(ptr, &n);
- if(!(map = apck_map_new(buf[3], tw, th, w, h, n, ptr)))
- return NULL;
- ptr += n;
- for(j = 0; j < l; j++) {
- ptr = apck_uleb128(ptr, &type);
- ptr = apck_uleb128(ptr, &disptype);
- ptr = apck_uleb128(ptr, &offX);
- ptr = apck_uleb128(ptr, &offY);
- ptr = apck_uleb128(ptr, &parX);
- ptr = apck_uleb128(ptr, &parY);
- ptr = apck_uleb128(ptr, &movX);
- ptr = apck_uleb128(ptr, &movY);
- if(type != APCK_MAP)
- ptr = apck_uleb128(ptr, &s);
- else
- s = 0;
- if((layer = apck_map_layer(map, type, s,
- type >= APCK_OBJECT ? ptr : (type != APCK_MAP && type != APCK_SPRITE && str && s ? str + s : NULL)))) {
- layer->disptype = disptype;
- layer->offX = offX; layer->offY = offY;
- layer->parX = parX; layer->parY = parY;
- layer->movX = movX - 100; layer->movY = movY - 100;
- if(type == APCK_MAP) {
- data = (uint32_t*)layer->data;
- for(i = 0, n = w * h; i < n;) {
- s = ((*ptr++) & 0x7F) + 1;
- if(ptr[-1] & 0x80) {
- ptr = apck_uleb128(ptr, &k);
- while(s-- && i < n) { data[i++] = k; }
- } else
- while(s-- && i < n) { ptr = apck_uleb128(ptr, &k); data[i++] = k; }
- }
- } else
- if(type == APCK_SPRITE) {
- list = (apck_map_list_t*)layer->data;
- for(i = 0; i < s; i++) {
- ptr = apck_uleb128(ptr, &k); list[i].v = str + k;
- ptr = apck_uleb128(ptr, &k); list[i].x = k;
- ptr = apck_uleb128(ptr, &k); list[i].y = k;
- }
- } else
- if(type >= APCK_OBJECT)
- ptr += s;
- } else
- break;
- }
- return map;
- }
- #endif
- #endif
- /**************** embeded apck_locale.h ****************/
- #ifndef APCK_LOCALE_H
- #define APCK_LOCALE_H
- int apck_setlocale(apck_t *ctx, char *locale);
- char *apck_msgstr(apck_t *ctx, char *msgid);
- #ifdef APCK_IMPLEMENTATION
- static char *_apck_sort_msgid = NULL;
- int _apck_msgidcmp(const void *a, const void *b)
- {
- if(!_apck_sort_msgid) return 0;
- return strcmp(_apck_sort_msgid + *((uint32_t*)a), _apck_sort_msgid + *((uint32_t*)b));
- }
- static int _apck_merge_locale(apck_t *ctx, uint32_t locale, char *str, uint32_t size)
- {
- char *msgid, *msgstr, *ptr, *end;
- int i;
- if(!(ctx->files[locale][0].buf = (uint8_t*)realloc(ctx->files[locale][0].buf, ctx->files[locale][0].size + size))) {
- DBG(("unable to allocate memory for locale %u strings\n", locale));
- return 0;
- }
- _apck_sort_msgid = (char*)ctx->files[locale][0].buf;
- ptr = (char*)ctx->files[locale][0].buf + ctx->files[locale][0].size;
- end = ptr + size;
- memcpy(ptr, str, size);
- ctx->files[locale][0].size += size;
- while(ptr < end) {
- msgid = ptr; ptr += strlen(ptr) + 1;
- msgstr = ptr; ptr += strlen(ptr) + 1;
- for(i = 0; i < ctx->files[locale][0].w && strcmp(_apck_sort_msgid + ctx->msgstr[locale][i * 2], msgid); i++);
- if(i >= ctx->files[locale][0].w) {
- i = ctx->files[locale][0].w++;
- if(!(ctx->msgstr[locale] = (uint32_t*)realloc(ctx->msgstr[locale], ctx->files[locale][0].w * 2 * sizeof(uint32_t)))) {
- DBG(("unable to allocate memory for locale %u index\n", locale));
- ctx->files[locale][0].w = 0;
- return 0;
- }
- ctx->msgstr[locale][i * 2] = msgid - _apck_sort_msgid;
- }
- ctx->msgstr[locale][i * 2 + 1] = msgstr - _apck_sort_msgid;
- }
- if(ctx->files[locale][0].w && ctx->msgstr[locale])
- qsort(ctx->msgstr[locale], ctx->files[locale][0].w, 2 * sizeof(uint32_t), _apck_msgidcmp);
- return 1;
- }
- int apck_setlocale(apck_t *ctx, char *locale)
- {
- uint32_t i;
- if(!ctx || !locale || !*locale) return APCK_ERR_BADINP;
- for(i = 0; i < APCK_FONT && ctx->files[i] && strcmp(ctx->files[i][0].name, locale); i++);
- if(i >= APCK_FONT) {
- for(i = 0; i < APCK_FONT && ctx->files[i] && memcmp(ctx->files[i][0].name, locale, 2); i++);
- if(i >= APCK_FONT) return APCK_ERR_BADINP;
- }
- if(!ctx->msgstr[i]) return APCK_ERR_BADINP;
- ctx->locale = i;
- return APCK_OK;
- }
- char *apck_msgstr(apck_t *ctx, char *msgid)
- {
- uint32_t *idx;
- char *str;
- int s = 0, e, h, m;
- if(!ctx || !msgid || !*msgid || ctx->locale >= APCK_FONT || !ctx->msgstr[ctx->locale] ||
- !ctx->files[ctx->locale] || !ctx->files[ctx->locale][0].w || !ctx->files[ctx->locale][0].buf)
- return msgid;
- str = (char*)ctx->files[ctx->locale][0].buf;
- idx = ctx->msgstr[ctx->locale];
- e = ctx->files[ctx->locale][0].w - 1;
- while(s <= e) {
- h = ((e + s) >> 1);
- m = strcmp(str + idx[h * 2], msgid);
- if(!m) return str + idx[h * 2 + 1];
- if(m > 0) e = h - 1; else s = h + 1;
- }
- return msgid;
- }
- #endif
- #endif
- /**************** embeded apck_sprite.h ****************/
- #ifndef APCK_SPRITE_H
- #define APCK_SPRITE_H
- enum { APCK_ANIM_LOOP, APCK_ANIM_ONCE, APCK_ANIM_BF, APCK_TILE_WANG, APCK_TILE_WALL };
- enum { APCK_DIR_S, APCK_DIR_SW, APCK_DIR_W, APCK_DIR_NW, APCK_DIR_N, APCK_DIR_NE, APCK_DIR_E, APCK_DIR_SE, APCK_NUMDIR };
- enum { APCK_M_COPY, APCK_M_FLIPV, APCK_M_FLIPH, APCK_M_ROT90, APCK_M_ROT180, APCK_M_ROT270 };
- typedef struct {
- int atlas, m, w, h, sx, sy, dx, dy, dur;
- void *sfx;
- } apck_frame_t;
- typedef struct {
- int type, w, h, nf[APCK_NUMDIR];
- apck_frame_t *frames[APCK_NUMDIR];
- } apck_sprite_t;
- apck_sprite_t *apck_sprite_new(int type, int w, int h);
- int apck_sprite_frame(apck_sprite_t *sprite, int dir, int atlas, int m, int w, int h, int sx, int sy, int dx, int dy, int dur, char *sfx);
- int apck_sprite_free(apck_sprite_t *sprite);
- apck_sprite_t *apck_sprite_decode(uint32_t archive, uint8_t *str, uint8_t *buf, uint64_t size);
- void apck_sprite_pose(apck_t *ctx, apck_sprite_t *sprite, int dir, int frame, uint32_t *buf, int x, int y, int w, int h, int p);
- #ifdef APCK_IMPLEMENTATION
- apck_sprite_t *apck_sprite_new(int type, int w, int h)
- {
- apck_sprite_t *ret;
- if(w < 1 || w > 65535 || h < 1 || h > 65535 || !(ret = (apck_sprite_t*)malloc(sizeof(apck_sprite_t))))
- return NULL;
- memset(ret, 0, sizeof(apck_sprite_t));
- ret->type = type < APCK_ANIM_LOOP || type > APCK_ANIM_BF ? APCK_ANIM_LOOP : type;
- ret->w = w;
- ret->h = h;
- return ret;
- }
- int apck_sprite_frame(apck_sprite_t *sprite, int dir, int atlas, int m, int w, int h, int sx, int sy, int dx, int dy, int dur, char *sfx)
- {
- int i;
- if(!sprite || dir < APCK_DIR_S || dir >= APCK_NUMDIR || m < APCK_M_COPY || m > APCK_M_ROT270 ||
- w < 1 || h < 1 || sx < 0 || sy < 0 || dx < 0 || dx >= sprite->w || dy < 0 || dy >= sprite->h)
- return APCK_ERR_BADINP;
- if(dur < 1) dur = 1;
- if(dur > 65535) dur = 65535;
- if(dx + w > sprite->w) w = sprite->w - dx;
- if(dy + h > sprite->h) h = sprite->h - dy;
- i = sprite->nf[dir]++;
- if(!(sprite->frames[dir] = (apck_frame_t*)realloc(sprite->frames[dir], sprite->nf[dir] * sizeof(apck_frame_t)))) {
- sprite->nf[dir] = 0;
- return APCK_ERR_NOMEM;
- }
- sprite->frames[dir][i].m = m;
- sprite->frames[dir][i].w = w;
- sprite->frames[dir][i].h = h;
- sprite->frames[dir][i].sx = sx;
- sprite->frames[dir][i].sy = sy;
- sprite->frames[dir][i].dx = dx;
- sprite->frames[dir][i].dy = dy;
- sprite->frames[dir][i].dur = dur;
- sprite->frames[dir][i].atlas = atlas;
- sprite->frames[dir][i].sfx = sfx;
- return APCK_OK;
- }
- int apck_sprite_free(apck_sprite_t *sprite)
- {
- int i;
- if(!sprite) return APCK_ERR_BADINP;
- for(i = 0; i < APCK_NUMDIR; i++)
- if(sprite->frames[i])
- free(sprite->frames[i]);
- free(sprite);
- return APCK_OK;
- }
- apck_sprite_t *apck_sprite_decode(uint32_t aidx, uint8_t *str, uint8_t *buf, uint64_t size)
- {
- apck_sprite_t *sprite = NULL;
- uint64_t i, j, k, w, h, t, l;
- uint8_t *ptr = buf + 4;
- if(!str || !buf || !size || memcmp(buf, "SPFR", 4)) return NULL;
- ptr = apck_uleb128(ptr, &t);
- ptr = apck_uleb128(ptr, &w);
- ptr = apck_uleb128(ptr, &h);
- if(!(sprite = apck_sprite_new(t, w, h)))
- return NULL;
- for(j = 0; j < APCK_NUMDIR; j++) {
- ptr = apck_uleb128(ptr, &l);
- sprite->nf[j] = l;
- if((sprite->frames[j] = (apck_frame_t*)realloc(sprite->frames[j], sprite->nf[j] * sizeof(apck_frame_t)))) {
- for(i = 0; i < l; i++) {
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].atlas = aidx + k;
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].m = k;
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].w = k;
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].h = k;
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].sx = k;
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].sy = k;
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].dx = k;
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].dy = k;
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].dur = k;
- ptr = apck_uleb128(ptr, &k); sprite->frames[j][i].sfx = str && k ? str + k : NULL;
- }
- } else
- sprite->nf[j] = 0;
- }
- return sprite;
- }
- void apck_sprite_pose(apck_t *ctx, apck_sprite_t *sprite, int dir, int frame, uint32_t *buf, int x, int y, int w, int h, int p)
- {
- apck_file_t *atlas;
- apck_frame_t *f;
- uint8_t *fbuf;
- uint32_t *src, *dst;
- int X, Y, W, H;
- if(!sprite || dir < APCK_DIR_S || dir >= APCK_NUMDIR || frame < 0 || !sprite->frames[dir] || !buf || w < 1 || h < 1 ||
- p < 4 || x >= w || y >= h)
- return;
- p >>= 2;
- f = &sprite->frames[dir][frame % sprite->nf[dir]];
- if(f->atlas >= (int)ctx->numfiles[APCK_ATLAS]) return;
- atlas = &ctx->files[APCK_ATLAS][f->atlas];
- if(!atlas->buf || !atlas->w || !atlas->h) {
- if(atlas->size && (fbuf = apck_readbuf(ctx, atlas->archive, atlas->offs, atlas->size))) {
- if(!(atlas->buf = (uint8_t*)stbi_load_from_memory(fbuf, atlas->size, &atlas->w, &atlas->h, &W, 4)))
- atlas->size = atlas->comp = atlas->w = atlas->h = 0;
- free(fbuf);
- }
- if(!atlas->buf || !atlas->w || !atlas->h) return;
- }
- W = f->w;
- if(x + W > w) W = w - x;
- if(f->sx + W > atlas->w) W = atlas->w - f->sx;
- H = f->h;
- if(y + H > h) H = h - y;
- if(f->sy + H > atlas->h) H = atlas->h - f->sy;
- if(W < 1 || H < 1) return;
- src = (uint32_t*)atlas->buf + f->sy * atlas->w + f->sx;
- dst = buf + (y + f->dy) * p + x + f->dx;
- switch(f->m) {
- case APCK_M_ROT270:
- for(Y = 0; Y < H; Y++, dst += p)
- for(X = 0; X < W; X++)
- dst[X] = src[(H - 1 - X) * atlas->w + Y];
- break;
- case APCK_M_ROT180:
- src += (f->h - 1) * atlas->w;
- for(Y = 0; Y < H; Y++, src -= atlas->w, dst += p)
- for(X = 0; X < W; X++)
- dst[X] = src[f->w - 1 - X];
- break;
- case APCK_M_ROT90:
- for(Y = 0; Y < H; Y++, dst += p)
- for(X = 0; X < W; X++)
- dst[X] = src[X * atlas->w + f->w - 1 - Y];
- break;
- case APCK_M_FLIPH:
- src += (f->h - 1) * atlas->w;
- for(Y = 0; Y < H; Y++, src -= atlas->w, dst += p)
- memcpy(dst, src, W * 4);
- break;
- case APCK_M_FLIPV:
- for(Y = 0; Y < H; Y++, src += atlas->w, dst += p)
- for(X = 0; X < W; X++)
- dst[X] = src[f->w - 1 - X];
- break;
- default:
- for(Y = 0; Y < H; Y++, src += atlas->w, dst += p)
- memcpy(dst, src, W * 4);
- break;
- }
- }
- #endif
- #endif
- apck_map_t *apck_map(apck_t *ctx, char *name);
- #ifdef APCK_IMPLEMENTATION
- #define inline __inline__
- #ifndef STB_IMAGE_IMPLEMENTATION
- #define STB_IMAGE_IMPLEMENTATION
- #define STBI_NO_FAILURE_STRINGS
- #define STBI_NO_STDIO
- #define STBI_NO_LINEAR
- #define STBI_ONLY_PNG
- /* stb_image - v2.30 - public domain image loader - http://nothings.org/stb
- no warranty implied; use at your own risk
- https://github.com/nothings/stb */
- /**************** embeded stb_image.h ****************/
- #ifndef STBI_INCLUDE_STB_IMAGE_H
- #define STBI_INCLUDE_STB_IMAGE_H
- #define STBI_VERSION 1
- enum
- {
- STBI_default = 0,
- STBI_grey = 1,
- STBI_grey_alpha = 2,
- STBI_rgb = 3,
- STBI_rgb_alpha = 4
- };
- #include <stdlib.h>
- typedef unsigned char stbi_uc;
- typedef unsigned short stbi_us;
- #ifdef __cplusplus
- extern "C" {
- #endif
- #ifndef STBIDEF
- #ifdef STB_IMAGE_STATIC
- #define STBIDEF static
- #else
- #define STBIDEF extern
- #endif
- #endif
- typedef struct
- {
- int (*read) (void *user,char *data,int size);
- void (*skip) (void *user,int n);
- int (*eof) (void *user);
- } stbi_io_callbacks;
- STBIDEF stbi_uc *stbi_load_from_memory (stbi_uc const *buffer, int len , int *x, int *y, int *channels_in_file, int desired_channels);
- STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk , void *user, int *x, int *y, int *channels_in_file, int desired_channels);
- #ifdef STBI_WINDOWS_UTF8
- STBIDEF int stbi_convert_wchar_to_utf8(char *buffer, size_t bufferlen, const wchar_t* input);
- #endif
- STBIDEF stbi_us *stbi_load_16_from_memory (stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels);
- STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels);
- STBIDEF int stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
- STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
- STBIDEF const char *stbi_failure_reason (void);
- STBIDEF void stbi_image_free (void *retval_from_stbi_load);
- STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
- STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
- STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len);
- STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *clbk, void *user);
- STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
- STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
- STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
- STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply);
- STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert);
- STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip);
- STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
- STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
- STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
- STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
- STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
- STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
- #ifdef __cplusplus
- }
- #endif
- #endif
- #ifdef STB_IMAGE_IMPLEMENTATION
- #if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
- || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
- || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
- || defined(STBI_ONLY_ZLIB)
- #ifndef STBI_ONLY_JPEG
- #define STBI_NO_JPEG
- #endif
- #ifndef STBI_ONLY_PNG
- #define STBI_NO_PNG
- #endif
- #ifndef STBI_ONLY_BMP
- #define STBI_NO_BMP
- #endif
- #ifndef STBI_ONLY_PSD
- #define STBI_NO_PSD
- #endif
- #ifndef STBI_ONLY_TGA
- #define STBI_NO_TGA
- #endif
- #ifndef STBI_ONLY_GIF
- #define STBI_NO_GIF
- #endif
- #ifndef STBI_ONLY_HDR
- #define STBI_NO_HDR
- #endif
- #ifndef STBI_ONLY_PIC
- #define STBI_NO_PIC
- #endif
- #ifndef STBI_ONLY_PNM
- #define STBI_NO_PNM
- #endif
- #endif
- #if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
- #define STBI_NO_ZLIB
- #endif
- #include <stdarg.h>
- #include <stddef.h>
- #include <stdlib.h>
- #include <string.h>
- #include <limits.h>
- #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
- #include <math.h>
- #endif
- #ifndef STBI_ASSERT
- #include <assert.h>
- #define STBI_ASSERT(x) assert(x)
- #endif
- #ifdef __cplusplus
- #define STBI_EXTERN extern "C"
- #else
- #define STBI_EXTERN extern
- #endif
- #ifndef _MSC_VER
- #ifdef __cplusplus
- #define stbi_inline inline
- #else
- #define stbi_inline
- #endif
- #else
- #define stbi_inline __forceinline
- #endif
- #ifndef STBI_NO_THREAD_LOCALS
- #if defined(__cplusplus) && __cplusplus >= 201103L
- #define STBI_THREAD_LOCAL thread_local
- #elif defined(__GNUC__) && __GNUC__ < 5
- #define STBI_THREAD_LOCAL __thread
- #elif defined(_MSC_VER)
- #define STBI_THREAD_LOCAL __declspec(thread)
- #elif defined (__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
- #define STBI_THREAD_LOCAL _Thread_local
- #endif
- #ifndef STBI_THREAD_LOCAL
- #if defined(__GNUC__)
- #define STBI_THREAD_LOCAL __thread
- #endif
- #endif
- #endif
- #if defined(_MSC_VER) || defined(__SYMBIAN32__)
- typedef unsigned short stbi__uint16;
- typedef signed short stbi__int16;
- typedef unsigned int stbi__uint32;
- typedef signed int stbi__int32;
- #else
- #include <stdint.h>
- typedef uint16_t stbi__uint16;
- typedef int16_t stbi__int16;
- typedef uint32_t stbi__uint32;
- typedef int32_t stbi__int32;
- #endif
- typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
- #ifdef _MSC_VER
- #define STBI_NOTUSED(v) (void)(v)
- #else
- #define STBI_NOTUSED(v) (void)sizeof(v)
- #endif
- #ifdef _MSC_VER
- #define STBI_HAS_LROTL
- #endif
- #ifdef STBI_HAS_LROTL
- #define stbi_lrot(x,y) _lrotl(x,y)
- #else
- #define stbi_lrot(x,y) (((x) << (y)) | ((x) >> (-(y) & 31)))
- #endif
- #if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
- #elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
- #else
- #error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
- #endif
- #ifndef STBI_MALLOC
- #define STBI_MALLOC(sz) malloc(sz)
- #define STBI_REALLOC(p,newsz) realloc(p,newsz)
- #define STBI_FREE(p) free(p)
- #endif
- #ifndef STBI_REALLOC_SIZED
- #define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
- #endif
- #if defined(__x86_64__) || defined(_M_X64)
- #define STBI__X64_TARGET
- #elif defined(__i386) || defined(_M_IX86)
- #define STBI__X86_TARGET
- #endif
- #if defined(__GNUC__) && defined(STBI__X86_TARGET) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
- #define STBI_NO_SIMD
- #endif
- #if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
- #define STBI_NO_SIMD
- #endif
- #if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))
- #define STBI_SSE2
- #include <emmintrin.h>
- #ifdef _MSC_VER
- #if _MSC_VER >= 1400
- #include <intrin.h>
- static int stbi__cpuid3(void)
- {
- int info[4];
- __cpuid(info,1);
- return info[3];
- }
- #else
- static int stbi__cpuid3(void)
- {
- int res;
- __asm {
- mov eax,1
- cpuid
- mov res,edx
- }
- return res;
- }
- #endif
- #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
- #if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
- static int stbi__sse2_available(void)
- {
- int info3 = stbi__cpuid3();
- return ((info3 >> 26) & 1) != 0;
- }
- #endif
- #else
- #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
- #if !defined(STBI_NO_JPEG) && defined(STBI_SSE2)
- static int stbi__sse2_available(void)
- {
- return 1;
- }
- #endif
- #endif
- #endif
- #if defined(STBI_NO_SIMD) && defined(STBI_NEON)
- #undef STBI_NEON
- #endif
- #ifdef STBI_NEON
- #include <arm_neon.h>
- #ifdef _MSC_VER
- #define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
- #else
- #define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
- #endif
- #endif
- #ifndef STBI_SIMD_ALIGN
- #define STBI_SIMD_ALIGN(type, name) type name
- #endif
- #ifndef STBI_MAX_DIMENSIONS
- #define STBI_MAX_DIMENSIONS (1 << 24)
- #endif
- typedef struct
- {
- stbi__uint32 img_x, img_y;
- int img_n, img_out_n;
- stbi_io_callbacks io;
- void *io_user_data;
- int read_from_callbacks;
- int buflen;
- stbi_uc buffer_start[128];
- int callback_already_read;
- stbi_uc *img_buffer, *img_buffer_end;
- stbi_uc *img_buffer_original, *img_buffer_original_end;
- } stbi__context;
- static void stbi__refill_buffer(stbi__context *s);
- static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
- {
- s->io.read = NULL;
- s->read_from_callbacks = 0;
- s->callback_already_read = 0;
- s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
- s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
- }
- static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
- {
- s->io = *c;
- s->io_user_data = user;
- s->buflen = sizeof(s->buffer_start);
- s->read_from_callbacks = 1;
- s->callback_already_read = 0;
- s->img_buffer = s->img_buffer_original = s->buffer_start;
- stbi__refill_buffer(s);
- s->img_buffer_original_end = s->img_buffer_end;
- }
- static void stbi__rewind(stbi__context *s)
- {
- s->img_buffer = s->img_buffer_original;
- s->img_buffer_end = s->img_buffer_original_end;
- }
- enum
- {
- STBI_ORDER_RGB,
- STBI_ORDER_BGR
- };
- typedef struct
- {
- int bits_per_channel;
- int num_channels;
- int channel_order;
- } stbi__result_info;
- #ifndef STBI_NO_PNG
- static int stbi__png_test(stbi__context *s);
- static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri);
- static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
- static int stbi__png_is16(stbi__context *s);
- #endif
- static
- #ifdef STBI_THREAD_LOCAL
- STBI_THREAD_LOCAL
- #endif
- const char *stbi__g_failure_reason;
- STBIDEF const char *stbi_failure_reason(void)
- {
- return stbi__g_failure_reason;
- }
- #ifndef STBI_NO_FAILURE_STRINGS
- static int stbi__err(const char *str)
- {
- stbi__g_failure_reason = str;
- return 0;
- }
- #endif
- static void *stbi__malloc(size_t size)
- {
- return STBI_MALLOC(size);
- }
- static int stbi__addsizes_valid(int a, int b)
- {
- if (b < 0) return 0;
- return a <= INT_MAX - b;
- }
- static int stbi__mul2sizes_valid(int a, int b)
- {
- if (a < 0 || b < 0) return 0;
- if (b == 0) return 1;
- return a <= INT_MAX/b;
- }
- #if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
- static int stbi__mad2sizes_valid(int a, int b, int add)
- {
- return stbi__mul2sizes_valid(a, b) && stbi__addsizes_valid(a*b, add);
- }
- #endif
- static int stbi__mad3sizes_valid(int a, int b, int c, int add)
- {
- return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
- stbi__addsizes_valid(a*b*c, add);
- }
- #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)
- static int stbi__mad4sizes_valid(int a, int b, int c, int d, int add)
- {
- return stbi__mul2sizes_valid(a, b) && stbi__mul2sizes_valid(a*b, c) &&
- stbi__mul2sizes_valid(a*b*c, d) && stbi__addsizes_valid(a*b*c*d, add);
- }
- #endif
- #if !defined(STBI_NO_JPEG) || !defined(STBI_NO_PNG) || !defined(STBI_NO_TGA) || !defined(STBI_NO_HDR)
- static void *stbi__malloc_mad2(int a, int b, int add)
- {
- if (!stbi__mad2sizes_valid(a, b, add)) return NULL;
- return stbi__malloc(a*b + add);
- }
- #endif
- static void *stbi__malloc_mad3(int a, int b, int c, int add)
- {
- if (!stbi__mad3sizes_valid(a, b, c, add)) return NULL;
- return stbi__malloc(a*b*c + add);
- }
- #if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR) || !defined(STBI_NO_PNM)
- static void *stbi__malloc_mad4(int a, int b, int c, int d, int add)
- {
- if (!stbi__mad4sizes_valid(a, b, c, d, add)) return NULL;
- return stbi__malloc(a*b*c*d + add);
- }
- #endif
- #ifdef STBI_NO_FAILURE_STRINGS
- #define stbi__err(x,y) 0
- #elif defined(STBI_FAILURE_USERMSG)
- #define stbi__err(x,y) stbi__err(y)
- #else
- #define stbi__err(x,y) stbi__err(x)
- #endif
- #define stbi__errpf(x,y) ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))
- #define stbi__errpuc(x,y) ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
- STBIDEF void stbi_image_free(void *retval_from_stbi_load)
- {
- STBI_FREE(retval_from_stbi_load);
- }
- static int stbi__vertically_flip_on_load_global = 0;
- STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
- {
- stbi__vertically_flip_on_load_global = flag_true_if_should_flip;
- }
- #ifndef STBI_THREAD_LOCAL
- #define stbi__vertically_flip_on_load stbi__vertically_flip_on_load_global
- #else
- static STBI_THREAD_LOCAL int stbi__vertically_flip_on_load_local, stbi__vertically_flip_on_load_set;
- STBIDEF void stbi_set_flip_vertically_on_load_thread(int flag_true_if_should_flip)
- {
- stbi__vertically_flip_on_load_local = flag_true_if_should_flip;
- stbi__vertically_flip_on_load_set = 1;
- }
- #define stbi__vertically_flip_on_load (stbi__vertically_flip_on_load_set \
- ? stbi__vertically_flip_on_load_local \
- : stbi__vertically_flip_on_load_global)
- #endif
- static void *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri, int bpc)
- {
- memset(ri, 0, sizeof(*ri));
- ri->bits_per_channel = 8;
- ri->channel_order = STBI_ORDER_RGB;
- ri->num_channels = 0;
- #ifndef STBI_NO_PNG
- if (stbi__png_test(s)) return stbi__png_load(s,x,y,comp,req_comp, ri);
- #endif
- (void)bpc;
- return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
- }
- static stbi_uc *stbi__convert_16_to_8(stbi__uint16 *orig, int w, int h, int channels)
- {
- int i;
- int img_len = w * h * channels;
- stbi_uc *reduced;
- reduced = (stbi_uc *) stbi__malloc(img_len);
- if (reduced == NULL) return stbi__errpuc("outofmem", "Out of memory");
- for (i = 0; i < img_len; ++i)
- reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF);
- STBI_FREE(orig);
- return reduced;
- }
- static stbi__uint16 *stbi__convert_8_to_16(stbi_uc *orig, int w, int h, int channels)
- {
- int i;
- int img_len = w * h * channels;
- stbi__uint16 *enlarged;
- enlarged = (stbi__uint16 *) stbi__malloc(img_len*2);
- if (enlarged == NULL) return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
- for (i = 0; i < img_len; ++i)
- enlarged[i] = (stbi__uint16)((orig[i] << 8) + orig[i]);
- STBI_FREE(orig);
- return enlarged;
- }
- static void stbi__vertical_flip(void *image, int w, int h, int bytes_per_pixel)
- {
- int row;
- size_t bytes_per_row = (size_t)w * bytes_per_pixel;
- stbi_uc temp[2048];
- stbi_uc *bytes = (stbi_uc *)image;
- for (row = 0; row < (h>>1); row++) {
- stbi_uc *row0 = bytes + row*bytes_per_row;
- stbi_uc *row1 = bytes + (h - row - 1)*bytes_per_row;
- size_t bytes_left = bytes_per_row;
- while (bytes_left) {
- size_t bytes_copy = (bytes_left < sizeof(temp)) ? bytes_left : sizeof(temp);
- memcpy(temp, row0, bytes_copy);
- memcpy(row0, row1, bytes_copy);
- memcpy(row1, temp, bytes_copy);
- row0 += bytes_copy;
- row1 += bytes_copy;
- bytes_left -= bytes_copy;
- }
- }
- }
- static unsigned char *stbi__load_and_postprocess_8bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
- {
- stbi__result_info ri;
- void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 8);
- if (result == NULL)
- return NULL;
- STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
- if (ri.bits_per_channel != 8) {
- result = stbi__convert_16_to_8((stbi__uint16 *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
- ri.bits_per_channel = 8;
- }
- if (stbi__vertically_flip_on_load) {
- int channels = req_comp ? req_comp : *comp;
- stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi_uc));
- }
- return (unsigned char *) result;
- }
- static stbi__uint16 *stbi__load_and_postprocess_16bit(stbi__context *s, int *x, int *y, int *comp, int req_comp)
- {
- stbi__result_info ri;
- void *result = stbi__load_main(s, x, y, comp, req_comp, &ri, 16);
- if (result == NULL)
- return NULL;
- STBI_ASSERT(ri.bits_per_channel == 8 || ri.bits_per_channel == 16);
- if (ri.bits_per_channel != 16) {
- result = stbi__convert_8_to_16((stbi_uc *) result, *x, *y, req_comp == 0 ? *comp : req_comp);
- ri.bits_per_channel = 16;
- }
- if (stbi__vertically_flip_on_load) {
- int channels = req_comp ? req_comp : *comp;
- stbi__vertical_flip(result, *x, *y, channels * sizeof(stbi__uint16));
- }
- return (stbi__uint16 *) result;
- }
- #if !defined(STBI_NO_HDR) && !defined(STBI_NO_LINEAR)
- static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
- {
- if (stbi__vertically_flip_on_load && result != NULL) {
- int channels = req_comp ? req_comp : *comp;
- stbi__vertical_flip(result, *x, *y, channels * sizeof(float));
- }
- }
- #endif
- STBIDEF stbi_us *stbi_load_16_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *channels_in_file, int desired_channels)
- {
- stbi__context s;
- stbi__start_mem(&s,buffer,len);
- return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
- }
- STBIDEF stbi_us *stbi_load_16_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *channels_in_file, int desired_channels)
- {
- stbi__context s;
- stbi__start_callbacks(&s, (stbi_io_callbacks *)clbk, user);
- return stbi__load_and_postprocess_16bit(&s,x,y,channels_in_file,desired_channels);
- }
- STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
- {
- stbi__context s;
- stbi__start_mem(&s,buffer,len);
- return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
- }
- STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
- {
- stbi__context s;
- stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
- return stbi__load_and_postprocess_8bit(&s,x,y,comp,req_comp);
- }
- static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
- STBIDEF void stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
- STBIDEF void stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
- enum
- {
- STBI__SCAN_load=0,
- STBI__SCAN_type,
- STBI__SCAN_header
- };
- static void stbi__refill_buffer(stbi__context *s)
- {
- int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
- s->callback_already_read += (int) (s->img_buffer - s->img_buffer_original);
- if (n == 0) {
- s->read_from_callbacks = 0;
- s->img_buffer = s->buffer_start;
- s->img_buffer_end = s->buffer_start+1;
- *s->img_buffer = 0;
- } else {
- s->img_buffer = s->buffer_start;
- s->img_buffer_end = s->buffer_start + n;
- }
- }
- stbi_inline static stbi_uc stbi__get8(stbi__context *s)
- {
- if (s->img_buffer < s->img_buffer_end)
- return *s->img_buffer++;
- if (s->read_from_callbacks) {
- stbi__refill_buffer(s);
- return *s->img_buffer++;
- }
- return 0;
- }
- #if defined(STBI_NO_JPEG) && defined(STBI_NO_HDR) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
- #else
- stbi_inline static int stbi__at_eof(stbi__context *s)
- {
- if (s->io.read) {
- if (!(s->io.eof)(s->io_user_data)) return 0;
- if (s->read_from_callbacks == 0) return 1;
- }
- return s->img_buffer >= s->img_buffer_end;
- }
- #endif
- #if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC)
- #else
- static void stbi__skip(stbi__context *s, int n)
- {
- if (n == 0) return;
- if (n < 0) {
- s->img_buffer = s->img_buffer_end;
- return;
- }
- if (s->io.read) {
- int blen = (int) (s->img_buffer_end - s->img_buffer);
- if (blen < n) {
- s->img_buffer = s->img_buffer_end;
- (s->io.skip)(s->io_user_data, n - blen);
- return;
- }
- }
- s->img_buffer += n;
- }
- #endif
- #if defined(STBI_NO_PNG) && defined(STBI_NO_TGA) && defined(STBI_NO_HDR) && defined(STBI_NO_PNM)
- #else
- static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
- {
- if (s->io.read) {
- int blen = (int) (s->img_buffer_end - s->img_buffer);
- if (blen < n) {
- int res, count;
- memcpy(buffer, s->img_buffer, blen);
- count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
- res = (count == (n-blen));
- s->img_buffer = s->img_buffer_end;
- return res;
- }
- }
- if (s->img_buffer+n <= s->img_buffer_end) {
- memcpy(buffer, s->img_buffer, n);
- s->img_buffer += n;
- return 1;
- } else
- return 0;
- }
- #endif
- #if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
- #else
- static int stbi__get16be(stbi__context *s)
- {
- int z = stbi__get8(s);
- return (z << 8) + stbi__get8(s);
- }
- #endif
- #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD) && defined(STBI_NO_PIC)
- #else
- static stbi__uint32 stbi__get32be(stbi__context *s)
- {
- stbi__uint32 z = stbi__get16be(s);
- return (z << 16) + stbi__get16be(s);
- }
- #endif
- #if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
- #else
- static int stbi__get16le(stbi__context *s)
- {
- int z = stbi__get8(s);
- return z + (stbi__get8(s) << 8);
- }
- #endif
- #define STBI__BYTECAST(x) ((stbi_uc) ((x) & 255))
- #if defined(STBI_NO_JPEG) && defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
- #else
- static stbi_uc stbi__compute_y(int r, int g, int b)
- {
- return (stbi_uc) (((r*77) + (g*150) + (29*b)) >> 8);
- }
- #endif
- #if defined(STBI_NO_PNG) && defined(STBI_NO_BMP) && defined(STBI_NO_PSD) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF) && defined(STBI_NO_PIC) && defined(STBI_NO_PNM)
- #else
- static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
- {
- int i,j;
- unsigned char *good;
- if (req_comp == img_n) return data;
- STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
- good = (unsigned char *) stbi__malloc_mad3(req_comp, x, y, 0);
- if (good == NULL) {
- STBI_FREE(data);
- return stbi__errpuc("outofmem", "Out of memory");
- }
- for (j=0; j < (int) y; ++j) {
- unsigned char *src = data + j * x * img_n ;
- unsigned char *dest = good + j * x * req_comp;
- #define STBI__COMBO(a,b) ((a)*8+(b))
- #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
- switch (STBI__COMBO(img_n, req_comp)) {
- STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=255; } break;
- STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
- STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=255; } break;
- STBI__CASE(2,1) { dest[0]=src[0]; } break;
- STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
- STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break;
- STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=255; } break;
- STBI__CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
- STBI__CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = 255; } break;
- STBI__CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
- STBI__CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); dest[1] = src[3]; } break;
- STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break;
- default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return stbi__errpuc("unsupported", "Unsupported format conversion");
- }
- #undef STBI__CASE
- }
- STBI_FREE(data);
- return good;
- }
- #endif
- #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
- #else
- static stbi__uint16 stbi__compute_y_16(int r, int g, int b)
- {
- return (stbi__uint16) (((r*77) + (g*150) + (29*b)) >> 8);
- }
- #endif
- #if defined(STBI_NO_PNG) && defined(STBI_NO_PSD)
- #else
- static stbi__uint16 *stbi__convert_format16(stbi__uint16 *data, int img_n, int req_comp, unsigned int x, unsigned int y)
- {
- int i,j;
- stbi__uint16 *good;
- if (req_comp == img_n) return data;
- STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
- good = (stbi__uint16 *) stbi__malloc(req_comp * x * y * 2);
- if (good == NULL) {
- STBI_FREE(data);
- return (stbi__uint16 *) stbi__errpuc("outofmem", "Out of memory");
- }
- for (j=0; j < (int) y; ++j) {
- stbi__uint16 *src = data + j * x * img_n ;
- stbi__uint16 *dest = good + j * x * req_comp;
- #define STBI__COMBO(a,b) ((a)*8+(b))
- #define STBI__CASE(a,b) case STBI__COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
- switch (STBI__COMBO(img_n, req_comp)) {
- STBI__CASE(1,2) { dest[0]=src[0]; dest[1]=0xffff; } break;
- STBI__CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
- STBI__CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=0xffff; } break;
- STBI__CASE(2,1) { dest[0]=src[0]; } break;
- STBI__CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
- STBI__CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0]; dest[3]=src[1]; } break;
- STBI__CASE(3,4) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2];dest[3]=0xffff; } break;
- STBI__CASE(3,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
- STBI__CASE(3,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = 0xffff; } break;
- STBI__CASE(4,1) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); } break;
- STBI__CASE(4,2) { dest[0]=stbi__compute_y_16(src[0],src[1],src[2]); dest[1] = src[3]; } break;
- STBI__CASE(4,3) { dest[0]=src[0];dest[1]=src[1];dest[2]=src[2]; } break;
- default: STBI_ASSERT(0); STBI_FREE(data); STBI_FREE(good); return (stbi__uint16*) stbi__errpuc("unsupported", "Unsupported format conversion");
- }
- #undef STBI__CASE
- }
- STBI_FREE(data);
- return good;
- }
- #endif
- #ifndef STBI_NO_ZLIB
- #define STBI__ZFAST_BITS 9
- #define STBI__ZFAST_MASK ((1 << STBI__ZFAST_BITS) - 1)
- #define STBI__ZNSYMS 288
- typedef struct
- {
- stbi__uint16 fast[1 << STBI__ZFAST_BITS];
- stbi__uint16 firstcode[16];
- int maxcode[17];
- stbi__uint16 firstsymbol[16];
- stbi_uc size[STBI__ZNSYMS];
- stbi__uint16 value[STBI__ZNSYMS];
- } stbi__zhuffman;
- stbi_inline static int stbi__bitreverse16(int n)
- {
- n = ((n & 0xAAAA) >> 1) | ((n & 0x5555) << 1);
- n = ((n & 0xCCCC) >> 2) | ((n & 0x3333) << 2);
- n = ((n & 0xF0F0) >> 4) | ((n & 0x0F0F) << 4);
- n = ((n & 0xFF00) >> 8) | ((n & 0x00FF) << 8);
- return n;
- }
- stbi_inline static int stbi__bit_reverse(int v, int bits)
- {
- STBI_ASSERT(bits <= 16);
- return stbi__bitreverse16(v) >> (16-bits);
- }
- static int stbi__zbuild_huffman(stbi__zhuffman *z, const stbi_uc *sizelist, int num)
- {
- int i,k=0;
- int code, next_code[16], sizes[17];
- memset(sizes, 0, sizeof(sizes));
- memset(z->fast, 0, sizeof(z->fast));
- for (i=0; i < num; ++i)
- ++sizes[sizelist[i]];
- sizes[0] = 0;
- for (i=1; i < 16; ++i)
- if (sizes[i] > (1 << i))
- return stbi__err("bad sizes", "Corrupt PNG");
- code = 0;
- for (i=1; i < 16; ++i) {
- next_code[i] = code;
- z->firstcode[i] = (stbi__uint16) code;
- z->firstsymbol[i] = (stbi__uint16) k;
- code = (code + sizes[i]);
- if (sizes[i])
- if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
- z->maxcode[i] = code << (16-i);
- code <<= 1;
- k += sizes[i];
- }
- z->maxcode[16] = 0x10000;
- for (i=0; i < num; ++i) {
- int s = sizelist[i];
- if (s) {
- int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
- stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
- z->size [c] = (stbi_uc ) s;
- z->value[c] = (stbi__uint16) i;
- if (s <= STBI__ZFAST_BITS) {
- int j = stbi__bit_reverse(next_code[s],s);
- while (j < (1 << STBI__ZFAST_BITS)) {
- z->fast[j] = fastv;
- j += (1 << s);
- }
- }
- ++next_code[s];
- }
- }
- return 1;
- }
- typedef struct
- {
- stbi_uc *zbuffer, *zbuffer_end;
- int num_bits;
- int hit_zeof_once;
- stbi__uint32 code_buffer;
- char *zout;
- char *zout_start;
- char *zout_end;
- int z_expandable;
- stbi__zhuffman z_length, z_distance;
- } stbi__zbuf;
- stbi_inline static int stbi__zeof(stbi__zbuf *z)
- {
- return (z->zbuffer >= z->zbuffer_end);
- }
- stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
- {
- return stbi__zeof(z) ? 0 : *z->zbuffer++;
- }
- static void stbi__fill_bits(stbi__zbuf *z)
- {
- do {
- if (z->code_buffer >= (1U << z->num_bits)) {
- z->zbuffer = z->zbuffer_end;
- return;
- }
- z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
- z->num_bits += 8;
- } while (z->num_bits <= 24);
- }
- stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
- {
- unsigned int k;
- if (z->num_bits < n) stbi__fill_bits(z);
- k = z->code_buffer & ((1 << n) - 1);
- z->code_buffer >>= n;
- z->num_bits -= n;
- return k;
- }
- static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
- {
- int b,s,k;
- k = stbi__bit_reverse(a->code_buffer, 16);
- for (s=STBI__ZFAST_BITS+1; ; ++s)
- if (k < z->maxcode[s])
- break;
- if (s >= 16) return -1;
- b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
- if (b >= STBI__ZNSYMS) return -1;
- if (z->size[b] != s) return -1;
- a->code_buffer >>= s;
- a->num_bits -= s;
- return z->value[b];
- }
- stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
- {
- int b,s;
- if (a->num_bits < 16) {
- if (stbi__zeof(a)) {
- if (!a->hit_zeof_once) {
- a->hit_zeof_once = 1;
- a->num_bits += 16;
- } else {
- return -1;
- }
- } else {
- stbi__fill_bits(a);
- }
- }
- b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
- if (b) {
- s = b >> 9;
- a->code_buffer >>= s;
- a->num_bits -= s;
- return b & 511;
- }
- return stbi__zhuffman_decode_slowpath(a, z);
- }
- static int stbi__zexpand(stbi__zbuf *z, char *zout, int n)
- {
- char *q;
- unsigned int cur, limit, old_limit;
- z->zout = zout;
- if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
- cur = (unsigned int) (z->zout - z->zout_start);
- limit = old_limit = (unsigned) (z->zout_end - z->zout_start);
- if (UINT_MAX - cur < (unsigned) n) return stbi__err("outofmem", "Out of memory");
- while (cur + n > limit) {
- if(limit > UINT_MAX / 2) return stbi__err("outofmem", "Out of memory");
- limit *= 2;
- }
- q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
- STBI_NOTUSED(old_limit);
- if (q == NULL) return stbi__err("outofmem", "Out of memory");
- z->zout_start = q;
- z->zout = q + cur;
- z->zout_end = q + limit;
- return 1;
- }
- static const int stbi__zlength_base[31] = {
- 3,4,5,6,7,8,9,10,11,13,
- 15,17,19,23,27,31,35,43,51,59,
- 67,83,99,115,131,163,195,227,258,0,0 };
- static const int stbi__zlength_extra[31]=
- { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
- static const int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
- 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
- static const int stbi__zdist_extra[32] =
- { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
- static int stbi__parse_huffman_block(stbi__zbuf *a)
- {
- char *zout = a->zout;
- for(;;) {
- int z = stbi__zhuffman_decode(a, &a->z_length);
- if (z < 256) {
- if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
- if (zout >= a->zout_end) {
- if (!stbi__zexpand(a, zout, 1)) return 0;
- zout = a->zout;
- }
- *zout++ = (char) z;
- } else {
- stbi_uc *p;
- int len,dist;
- if (z == 256) {
- a->zout = zout;
- if (a->hit_zeof_once && a->num_bits < 16) {
- return stbi__err("unexpected end","Corrupt PNG");
- }
- return 1;
- }
- if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG");
- z -= 257;
- len = stbi__zlength_base[z];
- if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
- z = stbi__zhuffman_decode(a, &a->z_distance);
- if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG");
- dist = stbi__zdist_base[z];
- if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
- if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
- if (len > a->zout_end - zout) {
- if (!stbi__zexpand(a, zout, len)) return 0;
- zout = a->zout;
- }
- p = (stbi_uc *) (zout - dist);
- if (dist == 1) {
- stbi_uc v = *p;
- if (len) { do *zout++ = v; while (--len); }
- } else {
- if (len) { do *zout++ = *p++; while (--len); }
- }
- }
- }
- }
- static int stbi__compute_huffman_codes(stbi__zbuf *a)
- {
- static const stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
- stbi__zhuffman z_codelength;
- stbi_uc lencodes[286+32+137];
- stbi_uc codelength_sizes[19];
- int i,n;
- int hlit = stbi__zreceive(a,5) + 257;
- int hdist = stbi__zreceive(a,5) + 1;
- int hclen = stbi__zreceive(a,4) + 4;
- int ntot = hlit + hdist;
- memset(codelength_sizes, 0, sizeof(codelength_sizes));
- for (i=0; i < hclen; ++i) {
- int s = stbi__zreceive(a,3);
- codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
- }
- if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
- n = 0;
- while (n < ntot) {
- int c = stbi__zhuffman_decode(a, &z_codelength);
- if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
- if (c < 16)
- lencodes[n++] = (stbi_uc) c;
- else {
- stbi_uc fill = 0;
- if (c == 16) {
- c = stbi__zreceive(a,2)+3;
- if (n == 0) return stbi__err("bad codelengths", "Corrupt PNG");
- fill = lencodes[n-1];
- } else if (c == 17) {
- c = stbi__zreceive(a,3)+3;
- } else if (c == 18) {
- c = stbi__zreceive(a,7)+11;
- } else {
- return stbi__err("bad codelengths", "Corrupt PNG");
- }
- if (ntot - n < c) return stbi__err("bad codelengths", "Corrupt PNG");
- memset(lencodes+n, fill, c);
- n += c;
- }
- }
- if (n != ntot) return stbi__err("bad codelengths","Corrupt PNG");
- if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
- if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
- return 1;
- }
- static int stbi__parse_uncompressed_block(stbi__zbuf *a)
- {
- stbi_uc header[4];
- int len,nlen,k;
- if (a->num_bits & 7)
- stbi__zreceive(a, a->num_bits & 7);
- k = 0;
- while (a->num_bits > 0) {
- header[k++] = (stbi_uc) (a->code_buffer & 255);
- a->code_buffer >>= 8;
- a->num_bits -= 8;
- }
- if (a->num_bits < 0) return stbi__err("zlib corrupt","Corrupt PNG");
- while (k < 4)
- header[k++] = stbi__zget8(a);
- len = header[1] * 256 + header[0];
- nlen = header[3] * 256 + header[2];
- if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
- if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
- if (a->zout + len > a->zout_end)
- if (!stbi__zexpand(a, a->zout, len)) return 0;
- memcpy(a->zout, a->zbuffer, len);
- a->zbuffer += len;
- a->zout += len;
- return 1;
- }
- static int stbi__parse_zlib_header(stbi__zbuf *a)
- {
- int cmf = stbi__zget8(a);
- int cm = cmf & 15;
- int flg = stbi__zget8(a);
- if (stbi__zeof(a)) return stbi__err("bad zlib header","Corrupt PNG");
- if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG");
- if (flg & 32) return stbi__err("no preset dict","Corrupt PNG");
- if (cm != 8) return stbi__err("bad compression","Corrupt PNG");
- return 1;
- }
- static const stbi_uc stbi__zdefault_length[STBI__ZNSYMS] =
- {
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
- 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
- 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
- 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
- 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,
- 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8
- };
- static const stbi_uc stbi__zdefault_distance[32] =
- {
- 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5
- };
- static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
- {
- int final, type;
- if (parse_header)
- if (!stbi__parse_zlib_header(a)) return 0;
- a->num_bits = 0;
- a->code_buffer = 0;
- a->hit_zeof_once = 0;
- do {
- final = stbi__zreceive(a,1);
- type = stbi__zreceive(a,2);
- if (type == 0) {
- if (!stbi__parse_uncompressed_block(a)) return 0;
- } else if (type == 3) {
- return 0;
- } else {
- if (type == 1) {
- if (!stbi__zbuild_huffman(&a->z_length , stbi__zdefault_length , STBI__ZNSYMS)) return 0;
- if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance, 32)) return 0;
- } else {
- if (!stbi__compute_huffman_codes(a)) return 0;
- }
- if (!stbi__parse_huffman_block(a)) return 0;
- }
- } while (!final);
- return 1;
- }
- static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
- {
- a->zout_start = obuf;
- a->zout = obuf;
- a->zout_end = obuf + olen;
- a->z_expandable = exp;
- return stbi__parse_zlib(a, parse_header);
- }
- STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
- {
- stbi__zbuf a;
- char *p = (char *) stbi__malloc(initial_size);
- if (p == NULL) return NULL;
- a.zbuffer = (stbi_uc *) buffer;
- a.zbuffer_end = (stbi_uc *) buffer + len;
- if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {
- if (outlen) *outlen = (int) (a.zout - a.zout_start);
- return a.zout_start;
- } else {
- STBI_FREE(a.zout_start);
- return NULL;
- }
- }
- STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
- {
- return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
- }
- STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
- {
- stbi__zbuf a;
- char *p = (char *) stbi__malloc(initial_size);
- if (p == NULL) return NULL;
- a.zbuffer = (stbi_uc *) buffer;
- a.zbuffer_end = (stbi_uc *) buffer + len;
- if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
- if (outlen) *outlen = (int) (a.zout - a.zout_start);
- return a.zout_start;
- } else {
- STBI_FREE(a.zout_start);
- return NULL;
- }
- }
- STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
- {
- stbi__zbuf a;
- a.zbuffer = (stbi_uc *) ibuffer;
- a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
- if (stbi__do_zlib(&a, obuffer, olen, 0, 1))
- return (int) (a.zout - a.zout_start);
- else
- return -1;
- }
- STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
- {
- stbi__zbuf a;
- char *p = (char *) stbi__malloc(16384);
- if (p == NULL) return NULL;
- a.zbuffer = (stbi_uc *) buffer;
- a.zbuffer_end = (stbi_uc *) buffer+len;
- if (stbi__do_zlib(&a, p, 16384, 1, 0)) {
- if (outlen) *outlen = (int) (a.zout - a.zout_start);
- return a.zout_start;
- } else {
- STBI_FREE(a.zout_start);
- return NULL;
- }
- }
- STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
- {
- stbi__zbuf a;
- a.zbuffer = (stbi_uc *) ibuffer;
- a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
- if (stbi__do_zlib(&a, obuffer, olen, 0, 0))
- return (int) (a.zout - a.zout_start);
- else
- return -1;
- }
- #endif
- #ifndef STBI_NO_PNG
- typedef struct
- {
- stbi__uint32 length;
- stbi__uint32 type;
- } stbi__pngchunk;
- static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
- {
- stbi__pngchunk c;
- c.length = stbi__get32be(s);
- c.type = stbi__get32be(s);
- return c;
- }
- static int stbi__check_png_header(stbi__context *s)
- {
- static const stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
- int i;
- for (i=0; i < 8; ++i)
- if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
- return 1;
- }
- typedef struct
- {
- stbi__context *s;
- stbi_uc *idata, *expanded, *out;
- int depth;
- } stbi__png;
- enum {
- STBI__F_none=0,
- STBI__F_sub=1,
- STBI__F_up=2,
- STBI__F_avg=3,
- STBI__F_paeth=4,
- STBI__F_avg_first
- };
- static stbi_uc first_row_filter[5] =
- {
- STBI__F_none,
- STBI__F_sub,
- STBI__F_none,
- STBI__F_avg_first,
- STBI__F_sub
- };
- static int stbi__paeth(int a, int b, int c)
- {
- int thresh = c*3 - (a + b);
- int lo = a < b ? a : b;
- int hi = a < b ? b : a;
- int t0 = (hi <= thresh) ? lo : c;
- int t1 = (thresh <= lo) ? hi : t0;
- return t1;
- }
- static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
- static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n)
- {
- int i;
- if (img_n == 1) {
- for (i=x-1; i >= 0; --i) {
- dest[i*2+1] = 255;
- dest[i*2+0] = src[i];
- }
- } else {
- STBI_ASSERT(img_n == 3);
- for (i=x-1; i >= 0; --i) {
- dest[i*4+3] = 255;
- dest[i*4+2] = src[i*3+2];
- dest[i*4+1] = src[i*3+1];
- dest[i*4+0] = src[i*3+0];
- }
- }
- }
- static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
- {
- int bytes = (depth == 16 ? 2 : 1);
- stbi__context *s = a->s;
- stbi__uint32 i,j,stride = x*out_n*bytes;
- stbi__uint32 img_len, img_width_bytes;
- stbi_uc *filter_buf;
- int all_ok = 1;
- int k;
- int img_n = s->img_n;
- int output_bytes = out_n*bytes;
- int filter_bytes = img_n*bytes;
- int width = x;
- STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
- a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0);
- if (!a->out) return stbi__err("outofmem", "Out of memory");
- if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG");
- img_width_bytes = (((img_n * x * depth) + 7) >> 3);
- if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG");
- img_len = (img_width_bytes + 1) * y;
- if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
- filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0);
- if (!filter_buf) return stbi__err("outofmem", "Out of memory");
- if (depth < 8) {
- filter_bytes = 1;
- width = img_width_bytes;
- }
- for (j=0; j < y; ++j) {
- stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes;
- stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes;
- stbi_uc *dest = a->out + stride*j;
- int nk = width * filter_bytes;
- int filter = *raw++;
- if (filter > 4) {
- all_ok = stbi__err("invalid filter","Corrupt PNG");
- break;
- }
- if (j == 0) filter = first_row_filter[filter];
- switch (filter) {
- case STBI__F_none:
- memcpy(cur, raw, nk);
- break;
- case STBI__F_sub:
- memcpy(cur, raw, filter_bytes);
- for (k = filter_bytes; k < nk; ++k)
- cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]);
- break;
- case STBI__F_up:
- for (k = 0; k < nk; ++k)
- cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
- break;
- case STBI__F_avg:
- for (k = 0; k < filter_bytes; ++k)
- cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1));
- for (k = filter_bytes; k < nk; ++k)
- cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1));
- break;
- case STBI__F_paeth:
- for (k = 0; k < filter_bytes; ++k)
- cur[k] = STBI__BYTECAST(raw[k] + prior[k]);
- for (k = filter_bytes; k < nk; ++k)
- cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes]));
- break;
- case STBI__F_avg_first:
- memcpy(cur, raw, filter_bytes);
- for (k = filter_bytes; k < nk; ++k)
- cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1));
- break;
- }
- raw += nk;
- if (depth < 8) {
- stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1;
- stbi_uc *in = cur;
- stbi_uc *out = dest;
- stbi_uc inb = 0;
- stbi__uint32 nsmp = x*img_n;
- if (depth == 4) {
- for (i=0; i < nsmp; ++i) {
- if ((i & 1) == 0) inb = *in++;
- *out++ = scale * (inb >> 4);
- inb <<= 4;
- }
- } else if (depth == 2) {
- for (i=0; i < nsmp; ++i) {
- if ((i & 3) == 0) inb = *in++;
- *out++ = scale * (inb >> 6);
- inb <<= 2;
- }
- } else {
- STBI_ASSERT(depth == 1);
- for (i=0; i < nsmp; ++i) {
- if ((i & 7) == 0) inb = *in++;
- *out++ = scale * (inb >> 7);
- inb <<= 1;
- }
- }
- if (img_n != out_n)
- stbi__create_png_alpha_expand8(dest, dest, x, img_n);
- } else if (depth == 8) {
- if (img_n == out_n)
- memcpy(dest, cur, x*img_n);
- else
- stbi__create_png_alpha_expand8(dest, cur, x, img_n);
- } else if (depth == 16) {
- stbi__uint16 *dest16 = (stbi__uint16*)dest;
- stbi__uint32 nsmp = x*img_n;
- if (img_n == out_n) {
- for (i = 0; i < nsmp; ++i, ++dest16, cur += 2)
- *dest16 = (cur[0] << 8) | cur[1];
- } else {
- STBI_ASSERT(img_n+1 == out_n);
- if (img_n == 1) {
- for (i = 0; i < x; ++i, dest16 += 2, cur += 2) {
- dest16[0] = (cur[0] << 8) | cur[1];
- dest16[1] = 0xffff;
- }
- } else {
- STBI_ASSERT(img_n == 3);
- for (i = 0; i < x; ++i, dest16 += 4, cur += 6) {
- dest16[0] = (cur[0] << 8) | cur[1];
- dest16[1] = (cur[2] << 8) | cur[3];
- dest16[2] = (cur[4] << 8) | cur[5];
- dest16[3] = 0xffff;
- }
- }
- }
- }
- }
- STBI_FREE(filter_buf);
- if (!all_ok) return 0;
- return 1;
- }
- static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
- {
- int bytes = (depth == 16 ? 2 : 1);
- int out_bytes = out_n * bytes;
- stbi_uc *final;
- int p;
- if (!interlaced)
- return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
- final = (stbi_uc *) stbi__malloc_mad3(a->s->img_x, a->s->img_y, out_bytes, 0);
- if (!final) return stbi__err("outofmem", "Out of memory");
- for (p=0; p < 7; ++p) {
- int xorig[] = { 0,4,0,2,0,1,0 };
- int yorig[] = { 0,0,4,0,2,0,1 };
- int xspc[] = { 8,8,4,4,2,2,1 };
- int yspc[] = { 8,8,8,4,4,2,2 };
- int i,j,x,y;
- x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
- y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
- if (x && y) {
- stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
- if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
- STBI_FREE(final);
- return 0;
- }
- for (j=0; j < y; ++j) {
- for (i=0; i < x; ++i) {
- int out_y = j*yspc[p]+yorig[p];
- int out_x = i*xspc[p]+xorig[p];
- memcpy(final + out_y*a->s->img_x*out_bytes + out_x*out_bytes,
- a->out + (j*x+i)*out_bytes, out_bytes);
- }
- }
- STBI_FREE(a->out);
- image_data += img_len;
- image_data_len -= img_len;
- }
- }
- a->out = final;
- return 1;
- }
- static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
- {
- stbi__context *s = z->s;
- stbi__uint32 i, pixel_count = s->img_x * s->img_y;
- stbi_uc *p = z->out;
- STBI_ASSERT(out_n == 2 || out_n == 4);
- if (out_n == 2) {
- for (i=0; i < pixel_count; ++i) {
- p[1] = (p[0] == tc[0] ? 0 : 255);
- p += 2;
- }
- } else {
- for (i=0; i < pixel_count; ++i) {
- if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
- p[3] = 0;
- p += 4;
- }
- }
- return 1;
- }
- static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
- {
- stbi__context *s = z->s;
- stbi__uint32 i, pixel_count = s->img_x * s->img_y;
- stbi__uint16 *p = (stbi__uint16*) z->out;
- STBI_ASSERT(out_n == 2 || out_n == 4);
- if (out_n == 2) {
- for (i = 0; i < pixel_count; ++i) {
- p[1] = (p[0] == tc[0] ? 0 : 65535);
- p += 2;
- }
- } else {
- for (i = 0; i < pixel_count; ++i) {
- if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
- p[3] = 0;
- p += 4;
- }
- }
- return 1;
- }
- static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
- {
- stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
- stbi_uc *p, *temp_out, *orig = a->out;
- p = (stbi_uc *) stbi__malloc_mad2(pixel_count, pal_img_n, 0);
- if (p == NULL) return stbi__err("outofmem", "Out of memory");
- temp_out = p;
- if (pal_img_n == 3) {
- for (i=0; i < pixel_count; ++i) {
- int n = orig[i]*4;
- p[0] = palette[n ];
- p[1] = palette[n+1];
- p[2] = palette[n+2];
- p += 3;
- }
- } else {
- for (i=0; i < pixel_count; ++i) {
- int n = orig[i]*4;
- p[0] = palette[n ];
- p[1] = palette[n+1];
- p[2] = palette[n+2];
- p[3] = palette[n+3];
- p += 4;
- }
- }
- STBI_FREE(a->out);
- a->out = temp_out;
- STBI_NOTUSED(len);
- return 1;
- }
- static int stbi__unpremultiply_on_load_global = 0;
- static int stbi__de_iphone_flag_global = 0;
- STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
- {
- stbi__unpremultiply_on_load_global = flag_true_if_should_unpremultiply;
- }
- STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
- {
- stbi__de_iphone_flag_global = flag_true_if_should_convert;
- }
- #ifndef STBI_THREAD_LOCAL
- #define stbi__unpremultiply_on_load stbi__unpremultiply_on_load_global
- #define stbi__de_iphone_flag stbi__de_iphone_flag_global
- #else
- static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set;
- static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set;
- STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply)
- {
- stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply;
- stbi__unpremultiply_on_load_set = 1;
- }
- STBIDEF void stbi_convert_iphone_png_to_rgb_thread(int flag_true_if_should_convert)
- {
- stbi__de_iphone_flag_local = flag_true_if_should_convert;
- stbi__de_iphone_flag_set = 1;
- }
- #define stbi__unpremultiply_on_load (stbi__unpremultiply_on_load_set \
- ? stbi__unpremultiply_on_load_local \
- : stbi__unpremultiply_on_load_global)
- #define stbi__de_iphone_flag (stbi__de_iphone_flag_set \
- ? stbi__de_iphone_flag_local \
- : stbi__de_iphone_flag_global)
- #endif
- static void stbi__de_iphone(stbi__png *z)
- {
- stbi__context *s = z->s;
- stbi__uint32 i, pixel_count = s->img_x * s->img_y;
- stbi_uc *p = z->out;
- if (s->img_out_n == 3) {
- for (i=0; i < pixel_count; ++i) {
- stbi_uc t = p[0];
- p[0] = p[2];
- p[2] = t;
- p += 3;
- }
- } else {
- STBI_ASSERT(s->img_out_n == 4);
- if (stbi__unpremultiply_on_load) {
- for (i=0; i < pixel_count; ++i) {
- stbi_uc a = p[3];
- stbi_uc t = p[0];
- if (a) {
- stbi_uc half = a / 2;
- p[0] = (p[2] * 255 + half) / a;
- p[1] = (p[1] * 255 + half) / a;
- p[2] = ( t * 255 + half) / a;
- } else {
- p[0] = p[2];
- p[2] = t;
- }
- p += 4;
- }
- } else {
- for (i=0; i < pixel_count; ++i) {
- stbi_uc t = p[0];
- p[0] = p[2];
- p[2] = t;
- p += 4;
- }
- }
- }
- }
- #define STBI__PNG_TYPE(a,b,c,d) (((unsigned) (a) << 24) + ((unsigned) (b) << 16) + ((unsigned) (c) << 8) + (unsigned) (d))
- static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
- {
- stbi_uc palette[1024], pal_img_n=0;
- stbi_uc has_trans=0, tc[3]={0};
- stbi__uint16 tc16[3];
- stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
- int first=1,k,interlace=0, color=0, is_iphone=0;
- stbi__context *s = z->s;
- z->expanded = NULL;
- z->idata = NULL;
- z->out = NULL;
- if (!stbi__check_png_header(s)) return 0;
- if (scan == STBI__SCAN_type) return 1;
- for (;;) {
- stbi__pngchunk c = stbi__get_chunk_header(s);
- switch (c.type) {
- case STBI__PNG_TYPE('C','g','B','I'):
- is_iphone = 1;
- stbi__skip(s, c.length);
- break;
- case STBI__PNG_TYPE('I','H','D','R'): {
- int comp,filter;
- if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
- first = 0;
- if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
- s->img_x = stbi__get32be(s);
- s->img_y = stbi__get32be(s);
- if (s->img_y > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
- if (s->img_x > STBI_MAX_DIMENSIONS) return stbi__err("too large","Very large image (corrupt?)");
- z->depth = stbi__get8(s); if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16) return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
- color = stbi__get8(s); if (color > 6) return stbi__err("bad ctype","Corrupt PNG");
- if (color == 3 && z->depth == 16) return stbi__err("bad ctype","Corrupt PNG");
- if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
- comp = stbi__get8(s); if (comp) return stbi__err("bad comp method","Corrupt PNG");
- filter= stbi__get8(s); if (filter) return stbi__err("bad filter method","Corrupt PNG");
- interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
- if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
- if (!pal_img_n) {
- s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
- if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
- } else {
- s->img_n = 1;
- if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
- }
- break;
- }
- case STBI__PNG_TYPE('P','L','T','E'): {
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
- if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
- pal_len = c.length / 3;
- if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
- for (i=0; i < pal_len; ++i) {
- palette[i*4+0] = stbi__get8(s);
- palette[i*4+1] = stbi__get8(s);
- palette[i*4+2] = stbi__get8(s);
- palette[i*4+3] = 255;
- }
- break;
- }
- case STBI__PNG_TYPE('t','R','N','S'): {
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
- if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
- if (pal_img_n) {
- if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
- if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
- if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
- pal_img_n = 4;
- for (i=0; i < c.length; ++i)
- palette[i*4+3] = stbi__get8(s);
- } else {
- if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
- if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
- has_trans = 1;
- if (scan == STBI__SCAN_header) { ++s->img_n; return 1; }
- if (z->depth == 16) {
- for (k = 0; k < s->img_n && k < 3; ++k)
- tc16[k] = (stbi__uint16)stbi__get16be(s);
- } else {
- for (k = 0; k < s->img_n && k < 3; ++k)
- tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth];
- }
- }
- break;
- }
- case STBI__PNG_TYPE('I','D','A','T'): {
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
- if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
- if (scan == STBI__SCAN_header) {
- if (pal_img_n)
- s->img_n = pal_img_n;
- return 1;
- }
- if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes");
- if ((int)(ioff + c.length) < (int)ioff) return 0;
- if (ioff + c.length > idata_limit) {
- stbi__uint32 idata_limit_old = idata_limit;
- stbi_uc *p;
- if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
- while (ioff + c.length > idata_limit)
- idata_limit *= 2;
- STBI_NOTUSED(idata_limit_old);
- p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
- z->idata = p;
- }
- if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
- ioff += c.length;
- break;
- }
- case STBI__PNG_TYPE('I','E','N','D'): {
- stbi__uint32 raw_len, bpl;
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
- if (scan != STBI__SCAN_load) return 1;
- if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
- bpl = (s->img_x * z->depth + 7) / 8;
- raw_len = bpl * s->img_y * s->img_n + s->img_y;
- z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
- if (z->expanded == NULL) return 0;
- STBI_FREE(z->idata); z->idata = NULL;
- if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
- s->img_out_n = s->img_n+1;
- else
- s->img_out_n = s->img_n;
- if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
- if (has_trans) {
- if (z->depth == 16) {
- if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
- } else {
- if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
- }
- }
- if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
- stbi__de_iphone(z);
- if (pal_img_n) {
- s->img_n = pal_img_n;
- s->img_out_n = pal_img_n;
- if (req_comp >= 3) s->img_out_n = req_comp;
- if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
- return 0;
- } else if (has_trans) {
- ++s->img_n;
- }
- STBI_FREE(z->expanded); z->expanded = NULL;
- stbi__get32be(s);
- return 1;
- }
- default:
- if (first) return stbi__err("first not IHDR", "Corrupt PNG");
- if ((c.type & (1 << 29)) == 0) {
- #ifndef STBI_NO_FAILURE_STRINGS
- static char invalid_chunk[] = "XXXX PNG chunk not known";
- invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);
- invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);
- invalid_chunk[2] = STBI__BYTECAST(c.type >> 8);
- invalid_chunk[3] = STBI__BYTECAST(c.type >> 0);
- #endif
- return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type");
- }
- stbi__skip(s, c.length);
- break;
- }
- stbi__get32be(s);
- }
- }
- static void *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp, stbi__result_info *ri)
- {
- void *result=NULL;
- if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
- if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
- if (p->depth <= 8)
- ri->bits_per_channel = 8;
- else if (p->depth == 16)
- ri->bits_per_channel = 16;
- else
- return stbi__errpuc("bad bits_per_channel", "PNG not supported: unsupported color depth");
- result = p->out;
- p->out = NULL;
- if (req_comp && req_comp != p->s->img_out_n) {
- if (ri->bits_per_channel == 8)
- result = stbi__convert_format((unsigned char *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
- else
- result = stbi__convert_format16((stbi__uint16 *) result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
- p->s->img_out_n = req_comp;
- if (result == NULL) return result;
- }
- *x = p->s->img_x;
- *y = p->s->img_y;
- if (n) *n = p->s->img_n;
- }
- STBI_FREE(p->out); p->out = NULL;
- STBI_FREE(p->expanded); p->expanded = NULL;
- STBI_FREE(p->idata); p->idata = NULL;
- return result;
- }
- static void *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp, stbi__result_info *ri)
- {
- stbi__png p;
- p.s = s;
- return stbi__do_png(&p, x,y,comp,req_comp, ri);
- }
- static int stbi__png_test(stbi__context *s)
- {
- int r;
- r = stbi__check_png_header(s);
- stbi__rewind(s);
- return r;
- }
- static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
- {
- if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {
- stbi__rewind( p->s );
- return 0;
- }
- if (x) *x = p->s->img_x;
- if (y) *y = p->s->img_y;
- if (comp) *comp = p->s->img_n;
- return 1;
- }
- static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
- {
- stbi__png p;
- p.s = s;
- return stbi__png_info_raw(&p, x, y, comp);
- }
- static int stbi__png_is16(stbi__context *s)
- {
- stbi__png p;
- p.s = s;
- if (!stbi__png_info_raw(&p, NULL, NULL, NULL))
- return 0;
- if (p.depth != 16) {
- stbi__rewind(p.s);
- return 0;
- }
- return 1;
- }
- #endif
- static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
- {
- #ifndef STBI_NO_PNG
- if (stbi__png_info(s, x, y, comp)) return 1;
- #endif
- return stbi__err("unknown image type", "Image not of any known type, or corrupt");
- }
- static int stbi__is_16_main(stbi__context *s)
- {
- #ifndef STBI_NO_PNG
- if (stbi__png_is16(s)) return 1;
- #endif
- return 0;
- }
- STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
- {
- stbi__context s;
- stbi__start_mem(&s,buffer,len);
- return stbi__info_main(&s,x,y,comp);
- }
- STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
- {
- stbi__context s;
- stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
- return stbi__info_main(&s,x,y,comp);
- }
- STBIDEF int stbi_is_16_bit_from_memory(stbi_uc const *buffer, int len)
- {
- stbi__context s;
- stbi__start_mem(&s,buffer,len);
- return stbi__is_16_main(&s);
- }
- STBIDEF int stbi_is_16_bit_from_callbacks(stbi_io_callbacks const *c, void *user)
- {
- stbi__context s;
- stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
- return stbi__is_16_main(&s);
- }
- #endif
- #endif
- #ifndef APCK_OGG
- #define APCK_OGG stb_vorbis_decode_memory
- #define STB_VORBIS_NO_STDIO
- #define STB_VORBIS_NO_PUSHDATA_API
- #define STB_VORBIS_MAX_CHANNELS 8
- /* Ogg Vorbis audio decoder - v1.22 - public domain
- https://github.com/nothings/stb */
- /**************** embeded stb_vorbis.h ****************/
- #ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H
- #define STB_VORBIS_INCLUDE_STB_VORBIS_H
- #if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
- #define STB_VORBIS_NO_STDIO 1
- #endif
- #ifdef __cplusplus
- extern "C" {
- #endif
- typedef struct
- {
- char *alloc_buffer;
- int alloc_buffer_length_in_bytes;
- } stb_vorbis_alloc;
- typedef struct stb_vorbis stb_vorbis;
- typedef struct
- {
- unsigned int sample_rate;
- int channels;
- unsigned int setup_memory_required;
- unsigned int setup_temp_memory_required;
- unsigned int temp_memory_required;
- int max_frame_size;
- } stb_vorbis_info;
- typedef struct
- {
- char *vendor;
- int comment_list_length;
- char **comment_list;
- } stb_vorbis_comment;
- extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f);
- extern stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f);
- extern int stb_vorbis_get_error(stb_vorbis *f);
- extern void stb_vorbis_close(stb_vorbis *f);
- extern int stb_vorbis_get_sample_offset(stb_vorbis *f);
- extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f);
- #ifndef STB_VORBIS_NO_PULLDATA_API
- #if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
- extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output);
- #endif
- #if !defined(STB_VORBIS_NO_INTEGER_CONVERSION)
- extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output);
- #endif
- extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len,
- int *error, const stb_vorbis_alloc *alloc_buffer);
- extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number);
- extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number);
- extern int stb_vorbis_seek_start(stb_vorbis *f);
- extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f);
- extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f);
- extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output);
- #ifndef STB_VORBIS_NO_INTEGER_CONVERSION
- extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts);
- extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples);
- #endif
- extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats);
- extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples);
- #ifndef STB_VORBIS_NO_INTEGER_CONVERSION
- extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts);
- extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples);
- #endif
- #endif
- enum STBVorbisError
- {
- VORBIS__no_error,
- VORBIS_need_more_data=1,
- VORBIS_invalid_api_mixing,
- VORBIS_outofmem,
- VORBIS_feature_not_supported,
- VORBIS_too_many_channels,
- VORBIS_file_open_failure,
- VORBIS_seek_without_length,
- VORBIS_unexpected_eof=10,
- VORBIS_seek_invalid,
- VORBIS_invalid_setup=20,
- VORBIS_invalid_stream,
- VORBIS_missing_capture_pattern=30,
- VORBIS_invalid_stream_structure_version,
- VORBIS_continued_packet_flag_invalid,
- VORBIS_incorrect_stream_serial_number,
- VORBIS_invalid_first_page,
- VORBIS_bad_packet_type,
- VORBIS_cant_find_last_page,
- VORBIS_seek_failed,
- VORBIS_ogg_skeleton_not_supported
- };
- #ifdef __cplusplus
- }
- #endif
- #endif
- #ifndef STB_VORBIS_HEADER_ONLY
- #ifndef STB_VORBIS_MAX_CHANNELS
- #define STB_VORBIS_MAX_CHANNELS 16
- #endif
- #ifndef STB_VORBIS_PUSHDATA_CRC_COUNT
- #define STB_VORBIS_PUSHDATA_CRC_COUNT 4
- #endif
- #ifndef STB_VORBIS_FAST_HUFFMAN_LENGTH
- #define STB_VORBIS_FAST_HUFFMAN_LENGTH 10
- #endif
- #ifndef STB_VORBIS_FAST_HUFFMAN_INT
- #define STB_VORBIS_FAST_HUFFMAN_SHORT
- #endif
- #ifdef STB_VORBIS_CODEBOOK_SHORTS
- #error "STB_VORBIS_CODEBOOK_SHORTS is no longer supported as it produced incorrect results for some input formats"
- #endif
- #ifdef STB_VORBIS_NO_PULLDATA_API
- #define STB_VORBIS_NO_INTEGER_CONVERSION
- #define STB_VORBIS_NO_STDIO
- #endif
- #if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO)
- #define STB_VORBIS_NO_STDIO 1
- #endif
- #ifndef STB_VORBIS_NO_INTEGER_CONVERSION
- #ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT
- #ifndef STB_VORBIS_BIG_ENDIAN
- #define STB_VORBIS_ENDIAN 0
- #else
- #define STB_VORBIS_ENDIAN 1
- #endif
- #endif
- #endif
- #ifndef STB_VORBIS_NO_CRT
- #include <stdlib.h>
- #include <string.h>
- #include <assert.h>
- #include <math.h>
- #if defined(_MSC_VER) || defined(__MINGW32__)
- #include <malloc.h>
- #endif
- #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__)
- #include <alloca.h>
- #endif
- #else
- #define NULL 0
- #define malloc(s) 0
- #define free(s) ((void) 0)
- #define realloc(s) 0
- #endif
- #include <limits.h>
- #ifdef __MINGW32__
- #ifdef __forceinline
- #undef __forceinline
- #endif
- #define __forceinline
- #ifndef alloca
- #define alloca __builtin_alloca
- #endif
- #elif !defined(_MSC_VER)
- #if __GNUC__
- #define __forceinline inline
- #else
- #define __forceinline
- #endif
- #endif
- #if STB_VORBIS_MAX_CHANNELS > 256
- #error "Value of STB_VORBIS_MAX_CHANNELS outside of allowed range"
- #endif
- #if STB_VORBIS_FAST_HUFFMAN_LENGTH > 24
- #error "Value of STB_VORBIS_FAST_HUFFMAN_LENGTH outside of allowed range"
- #endif
- #if 0
- #include <crtdbg.h>
- #define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1])
- #else
- #define CHECK(f) ((void) 0)
- #endif
- #define MAX_BLOCKSIZE_LOG 13
- #define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG)
- typedef unsigned char uint8;
- typedef signed char int8;
- typedef unsigned short uint16;
- typedef signed short int16;
- typedef unsigned int uint32;
- typedef signed int int32;
- #ifndef TRUE
- #define TRUE 1
- #define FALSE 0
- #endif
- typedef float codetype;
- #ifdef _MSC_VER
- #define STBV_NOTUSED(v) (void)(v)
- #else
- #define STBV_NOTUSED(v) (void)sizeof(v)
- #endif
- #define FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH)
- #define FAST_HUFFMAN_TABLE_MASK (FAST_HUFFMAN_TABLE_SIZE - 1)
- typedef struct
- {
- int dimensions, entries;
- uint8 *codeword_lengths;
- float minimum_value;
- float delta_value;
- uint8 value_bits;
- uint8 lookup_type;
- uint8 sequence_p;
- uint8 sparse;
- uint32 lookup_values;
- codetype *multiplicands;
- uint32 *codewords;
- #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT
- int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE];
- #else
- int32 fast_huffman[FAST_HUFFMAN_TABLE_SIZE];
- #endif
- uint32 *sorted_codewords;
- int *sorted_values;
- int sorted_entries;
- } Codebook;
- typedef struct
- {
- uint8 order;
- uint16 rate;
- uint16 bark_map_size;
- uint8 amplitude_bits;
- uint8 amplitude_offset;
- uint8 number_of_books;
- uint8 book_list[16];
- } Floor0;
- typedef struct
- {
- uint8 partitions;
- uint8 partition_class_list[32];
- uint8 class_dimensions[16];
- uint8 class_subclasses[16];
- uint8 class_masterbooks[16];
- int16 subclass_books[16][8];
- uint16 Xlist[31*8+2];
- uint8 sorted_order[31*8+2];
- uint8 neighbors[31*8+2][2];
- uint8 floor1_multiplier;
- uint8 rangebits;
- int values;
- } Floor1;
- typedef union
- {
- Floor0 floor0;
- Floor1 floor1;
- } Floor;
- typedef struct
- {
- uint32 begin, end;
- uint32 part_size;
- uint8 classifications;
- uint8 classbook;
- uint8 **classdata;
- int16 (*residue_books)[8];
- } Residue;
- typedef struct
- {
- uint8 magnitude;
- uint8 angle;
- uint8 mux;
- } MappingChannel;
- typedef struct
- {
- uint16 coupling_steps;
- MappingChannel *chan;
- uint8 submaps;
- uint8 submap_floor[15];
- uint8 submap_residue[15];
- } Mapping;
- typedef struct
- {
- uint8 blockflag;
- uint8 mapping;
- uint16 windowtype;
- uint16 transformtype;
- } Mode;
- typedef struct
- {
- uint32 goal_crc;
- int bytes_left;
- uint32 crc_so_far;
- int bytes_done;
- uint32 sample_loc;
- } CRCscan;
- typedef struct
- {
- uint32 page_start, page_end;
- uint32 last_decoded_sample;
- } ProbedPage;
- struct stb_vorbis
- {
- unsigned int sample_rate;
- int channels;
- unsigned int setup_memory_required;
- unsigned int temp_memory_required;
- unsigned int setup_temp_memory_required;
- char *vendor;
- int comment_list_length;
- char **comment_list;
- uint8 *stream;
- uint8 *stream_start;
- uint8 *stream_end;
- uint32 stream_len;
- uint8 push_mode;
- uint32 first_audio_page_offset;
- ProbedPage p_first, p_last;
- stb_vorbis_alloc alloc;
- int setup_offset;
- int temp_offset;
- int eof;
- enum STBVorbisError error;
- int blocksize[2];
- int blocksize_0, blocksize_1;
- int codebook_count;
- Codebook *codebooks;
- int floor_count;
- uint16 floor_types[64];
- Floor *floor_config;
- int residue_count;
- uint16 residue_types[64];
- Residue *residue_config;
- int mapping_count;
- Mapping *mapping;
- int mode_count;
- Mode mode_config[64];
- uint32 total_samples;
- float *channel_buffers[STB_VORBIS_MAX_CHANNELS];
- float *outputs [STB_VORBIS_MAX_CHANNELS];
- float *previous_window[STB_VORBIS_MAX_CHANNELS];
- int previous_length;
- #ifndef STB_VORBIS_NO_DEFER_FLOOR
- int16 *finalY[STB_VORBIS_MAX_CHANNELS];
- #else
- float *floor_buffers[STB_VORBIS_MAX_CHANNELS];
- #endif
- uint32 current_loc;
- int current_loc_valid;
- float *A[2],*B[2],*C[2];
- float *window[2];
- uint16 *bit_reverse[2];
- uint32 serial;
- int last_page;
- int segment_count;
- uint8 segments[255];
- uint8 page_flag;
- uint8 bytes_in_seg;
- uint8 first_decode;
- int next_seg;
- int last_seg;
- int last_seg_which;
- uint32 acc;
- int valid_bits;
- int packet_bytes;
- int end_seg_with_known_loc;
- uint32 known_loc_for_packet;
- int discard_samples_deferred;
- uint32 samples_output;
- int page_crc_tests;
- int channel_buffer_start;
- int channel_buffer_end;
- };
- #if defined(STB_VORBIS_NO_PUSHDATA_API)
- #define IS_PUSH_MODE(f) FALSE
- #elif defined(STB_VORBIS_NO_PULLDATA_API)
- #define IS_PUSH_MODE(f) TRUE
- #else
- #define IS_PUSH_MODE(f) ((f)->push_mode)
- #endif
- typedef struct stb_vorbis vorb;
- static int error(vorb *f, enum STBVorbisError e)
- {
- f->error = e;
- if (!f->eof && e != VORBIS_need_more_data) {
- f->error=e;
- }
- return 0;
- }
- #define array_size_required(count,size) (count*(sizeof(void *)+(size)))
- #define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size))
- #define temp_free(f,p) (void)0
- #define temp_alloc_save(f) ((f)->temp_offset)
- #define temp_alloc_restore(f,p) ((f)->temp_offset = (p))
- #define temp_block_array(f,count,size) make_block_array(temp_alloc(f,array_size_required(count,size)), count, size)
- static void *make_block_array(void *mem, int count, int size)
- {
- int i;
- void ** p = (void **) mem;
- char *q = (char *) (p + count);
- for (i=0; i < count; ++i) {
- p[i] = q;
- q += size;
- }
- return p;
- }
- static void *setup_malloc(vorb *f, int sz)
- {
- sz = (sz+7) & ~7;
- f->setup_memory_required += sz;
- if (f->alloc.alloc_buffer) {
- void *p = (char *) f->alloc.alloc_buffer + f->setup_offset;
- if (f->setup_offset + sz > f->temp_offset) return NULL;
- f->setup_offset += sz;
- return p;
- }
- return sz ? malloc(sz) : NULL;
- }
- static void setup_free(vorb *f, void *p)
- {
- if (f->alloc.alloc_buffer) return;
- free(p);
- }
- static void *setup_temp_malloc(vorb *f, int sz)
- {
- sz = (sz+7) & ~7;
- if (f->alloc.alloc_buffer) {
- if (f->temp_offset - sz < f->setup_offset) return NULL;
- f->temp_offset -= sz;
- return (char *) f->alloc.alloc_buffer + f->temp_offset;
- }
- return malloc(sz);
- }
- static void setup_temp_free(vorb *f, void *p, int sz)
- {
- if (f->alloc.alloc_buffer) {
- f->temp_offset += (sz+7)&~7;
- return;
- }
- free(p);
- }
- #define CRC32_POLY 0x04c11db7
- static uint32 crc_table[256];
- static void crc32_init(void)
- {
- int i,j;
- uint32 s;
- for(i=0; i < 256; i++) {
- for (s=(uint32) i << 24, j=0; j < 8; ++j)
- s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0);
- crc_table[i] = s;
- }
- }
- static __forceinline uint32 crc32_update(uint32 crc, uint8 byte)
- {
- return (crc << 8) ^ crc_table[byte ^ (crc >> 24)];
- }
- static unsigned int bit_reverse(unsigned int n)
- {
- n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1);
- n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2);
- n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4);
- n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8);
- return (n >> 16) | (n << 16);
- }
- static float square(float x)
- {
- return x*x;
- }
- static int ilog(int32 n)
- {
- static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 };
- if (n < 0) return 0;
- if (n < (1 << 14))
- if (n < (1 << 4)) return 0 + log2_4[n ];
- else if (n < (1 << 9)) return 5 + log2_4[n >> 5];
- else return 10 + log2_4[n >> 10];
- else if (n < (1 << 24))
- if (n < (1 << 19)) return 15 + log2_4[n >> 15];
- else return 20 + log2_4[n >> 20];
- else if (n < (1 << 29)) return 25 + log2_4[n >> 25];
- else return 30 + log2_4[n >> 30];
- }
- #ifndef M_PI
- #define M_PI 3.14159265358979323846264f
- #endif
- #define NO_CODE 255
- static float float32_unpack(uint32 x)
- {
- uint32 mantissa = x & 0x1fffff;
- uint32 sign = x & 0x80000000;
- uint32 exp = (x & 0x7fe00000) >> 21;
- double res = sign ? -(double)mantissa : (double)mantissa;
- return (float) ldexp((float)res, (int)exp-788);
- }
- static void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int len, uint32 *values)
- {
- if (!c->sparse) {
- c->codewords [symbol] = huff_code;
- } else {
- c->codewords [count] = huff_code;
- c->codeword_lengths[count] = len;
- values [count] = symbol;
- }
- }
- static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values)
- {
- int i,k,m=0;
- uint32 available[32];
- memset(available, 0, sizeof(available));
- for (k=0; k < n; ++k) if (len[k] < NO_CODE) break;
- if (k == n) { assert(c->sorted_entries == 0); return TRUE; }
- assert(len[k] < 32);
- add_entry(c, 0, k, m++, len[k], values);
- for (i=1; i <= len[k]; ++i)
- available[i] = 1U << (32-i);
- for (i=k+1; i < n; ++i) {
- uint32 res;
- int z = len[i], y;
- if (z == NO_CODE) continue;
- assert(z < 32);
- while (z > 0 && !available[z]) --z;
- if (z == 0) { return FALSE; }
- res = available[z];
- available[z] = 0;
- add_entry(c, bit_reverse(res), i, m++, len[i], values);
- if (z != len[i]) {
- for (y=len[i]; y > z; --y) {
- assert(available[y] == 0);
- available[y] = res + (1 << (32-y));
- }
- }
- }
- return TRUE;
- }
- static void compute_accelerated_huffman(Codebook *c)
- {
- int i, len;
- for (i=0; i < FAST_HUFFMAN_TABLE_SIZE; ++i)
- c->fast_huffman[i] = -1;
- len = c->sparse ? c->sorted_entries : c->entries;
- #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT
- if (len > 32767) len = 32767;
- #endif
- for (i=0; i < len; ++i) {
- if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) {
- uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i];
- while (z < FAST_HUFFMAN_TABLE_SIZE) {
- c->fast_huffman[z] = i;
- z += 1 << c->codeword_lengths[i];
- }
- }
- }
- }
- #ifdef _MSC_VER
- #define STBV_CDECL __cdecl
- #else
- #define STBV_CDECL
- #endif
- static int STBV_CDECL uint32_compare(const void *p, const void *q)
- {
- uint32 x = * (uint32 *) p;
- uint32 y = * (uint32 *) q;
- return x < y ? -1 : x > y;
- }
- static int include_in_sort(Codebook *c, uint8 len)
- {
- if (c->sparse) { assert(len != NO_CODE); return TRUE; }
- if (len == NO_CODE) return FALSE;
- if (len > STB_VORBIS_FAST_HUFFMAN_LENGTH) return TRUE;
- return FALSE;
- }
- static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values)
- {
- int i, len;
- if (!c->sparse) {
- int k = 0;
- for (i=0; i < c->entries; ++i)
- if (include_in_sort(c, lengths[i]))
- c->sorted_codewords[k++] = bit_reverse(c->codewords[i]);
- assert(k == c->sorted_entries);
- } else {
- for (i=0; i < c->sorted_entries; ++i)
- c->sorted_codewords[i] = bit_reverse(c->codewords[i]);
- }
- qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare);
- c->sorted_codewords[c->sorted_entries] = 0xffffffff;
- len = c->sparse ? c->sorted_entries : c->entries;
- for (i=0; i < len; ++i) {
- int huff_len = c->sparse ? lengths[values[i]] : lengths[i];
- if (include_in_sort(c,huff_len)) {
- uint32 code = bit_reverse(c->codewords[i]);
- int x=0, n=c->sorted_entries;
- while (n > 1) {
- int m = x + (n >> 1);
- if (c->sorted_codewords[m] <= code) {
- x = m;
- n -= (n>>1);
- } else {
- n >>= 1;
- }
- }
- assert(c->sorted_codewords[x] == code);
- if (c->sparse) {
- c->sorted_values[x] = values[i];
- c->codeword_lengths[x] = huff_len;
- } else {
- c->sorted_values[x] = i;
- }
- }
- }
- }
- static int vorbis_validate(uint8 *data)
- {
- static uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' };
- return memcmp(data, vorbis, 6) == 0;
- }
- static int lookup1_values(int entries, int dim)
- {
- int r = (int) floor(exp((float) log((float) entries) / dim));
- if ((int) floor(pow((float) r+1, dim)) <= entries)
- ++r;
- if (pow((float) r+1, dim) <= entries)
- return -1;
- if ((int) floor(pow((float) r, dim)) > entries)
- return -1;
- return r;
- }
- static void compute_twiddle_factors(int n, float *A, float *B, float *C)
- {
- int n4 = n >> 2, n8 = n >> 3;
- int k,k2;
- for (k=k2=0; k < n4; ++k,k2+=2) {
- A[k2 ] = (float) cos(4*k*M_PI/n);
- A[k2+1] = (float) -sin(4*k*M_PI/n);
- B[k2 ] = (float) cos((k2+1)*M_PI/n/2) * 0.5f;
- B[k2+1] = (float) sin((k2+1)*M_PI/n/2) * 0.5f;
- }
- for (k=k2=0; k < n8; ++k,k2+=2) {
- C[k2 ] = (float) cos(2*(k2+1)*M_PI/n);
- C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n);
- }
- }
- static void compute_window(int n, float *window)
- {
- int n2 = n >> 1, i;
- for (i=0; i < n2; ++i)
- window[i] = (float) sin(0.5 * M_PI * square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI)));
- }
- static void compute_bitreverse(int n, uint16 *rev)
- {
- int ld = ilog(n) - 1;
- int i, n8 = n >> 3;
- for (i=0; i < n8; ++i)
- rev[i] = (bit_reverse(i) >> (32-ld+3)) << 2;
- }
- static int init_blocksize(vorb *f, int b, int n)
- {
- int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3;
- f->A[b] = (float *) setup_malloc(f, sizeof(float) * n2);
- f->B[b] = (float *) setup_malloc(f, sizeof(float) * n2);
- f->C[b] = (float *) setup_malloc(f, sizeof(float) * n4);
- if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem);
- compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]);
- f->window[b] = (float *) setup_malloc(f, sizeof(float) * n2);
- if (!f->window[b]) return error(f, VORBIS_outofmem);
- compute_window(n, f->window[b]);
- f->bit_reverse[b] = (uint16 *) setup_malloc(f, sizeof(uint16) * n8);
- if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem);
- compute_bitreverse(n, f->bit_reverse[b]);
- return TRUE;
- }
- static void neighbors(uint16 *x, int n, int *plow, int *phigh)
- {
- int low = -1;
- int high = 65536;
- int i;
- for (i=0; i < n; ++i) {
- if (x[i] > low && x[i] < x[n]) { *plow = i; low = x[i]; }
- if (x[i] < high && x[i] > x[n]) { *phigh = i; high = x[i]; }
- }
- }
- typedef struct
- {
- uint16 x,id;
- } stbv__floor_ordering;
- static int STBV_CDECL point_compare(const void *p, const void *q)
- {
- stbv__floor_ordering *a = (stbv__floor_ordering *) p;
- stbv__floor_ordering *b = (stbv__floor_ordering *) q;
- return a->x < b->x ? -1 : a->x > b->x;
- }
- #if defined(STB_VORBIS_NO_STDIO)
- #define USE_MEMORY(z) TRUE
- #else
- #define USE_MEMORY(z) ((z)->stream)
- #endif
- static uint8 get8(vorb *z)
- {
- if (USE_MEMORY(z)) {
- if (z->stream >= z->stream_end) { z->eof = TRUE; return 0; }
- return *z->stream++;
- }
- }
- static uint32 get32(vorb *f)
- {
- uint32 x;
- x = get8(f);
- x += get8(f) << 8;
- x += get8(f) << 16;
- x += (uint32) get8(f) << 24;
- return x;
- }
- static int getn(vorb *z, uint8 *data, int n)
- {
- if (USE_MEMORY(z)) {
- if (z->stream+n > z->stream_end) { z->eof = 1; return 0; }
- memcpy(data, z->stream, n);
- z->stream += n;
- return 1;
- }
- }
- static void skip(vorb *z, int n)
- {
- if (USE_MEMORY(z)) {
- z->stream += n;
- if (z->stream >= z->stream_end) z->eof = 1;
- return;
- }
- }
- static int set_file_offset(stb_vorbis *f, unsigned int loc)
- {
- f->eof = 0;
- if (USE_MEMORY(f)) {
- if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) {
- f->stream = f->stream_end;
- f->eof = 1;
- return 0;
- } else {
- f->stream = f->stream_start + loc;
- return 1;
- }
- }
- }
- static uint8 ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 };
- static int capture_pattern(vorb *f)
- {
- if (0x4f != get8(f)) return FALSE;
- if (0x67 != get8(f)) return FALSE;
- if (0x67 != get8(f)) return FALSE;
- if (0x53 != get8(f)) return FALSE;
- return TRUE;
- }
- #define PAGEFLAG_continued_packet 1
- #define PAGEFLAG_first_page 2
- #define PAGEFLAG_last_page 4
- static int start_page_no_capturepattern(vorb *f)
- {
- uint32 loc0,loc1,n;
- if (f->first_decode && !IS_PUSH_MODE(f)) {
- f->p_first.page_start = stb_vorbis_get_file_offset(f) - 4;
- }
- if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version);
- f->page_flag = get8(f);
- loc0 = get32(f);
- loc1 = get32(f);
- get32(f);
- n = get32(f);
- f->last_page = n;
- get32(f);
- f->segment_count = get8(f);
- if (!getn(f, f->segments, f->segment_count))
- return error(f, VORBIS_unexpected_eof);
- f->end_seg_with_known_loc = -2;
- if (loc0 != ~0U || loc1 != ~0U) {
- int i;
- for (i=f->segment_count-1; i >= 0; --i)
- if (f->segments[i] < 255)
- break;
- if (i >= 0) {
- f->end_seg_with_known_loc = i;
- f->known_loc_for_packet = loc0;
- }
- }
- if (f->first_decode) {
- int i,len;
- len = 0;
- for (i=0; i < f->segment_count; ++i)
- len += f->segments[i];
- len += 27 + f->segment_count;
- f->p_first.page_end = f->p_first.page_start + len;
- f->p_first.last_decoded_sample = loc0;
- }
- f->next_seg = 0;
- return TRUE;
- }
- static int start_page(vorb *f)
- {
- if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern);
- return start_page_no_capturepattern(f);
- }
- static int start_packet(vorb *f)
- {
- while (f->next_seg == -1) {
- if (!start_page(f)) return FALSE;
- if (f->page_flag & PAGEFLAG_continued_packet)
- return error(f, VORBIS_continued_packet_flag_invalid);
- }
- f->last_seg = FALSE;
- f->valid_bits = 0;
- f->packet_bytes = 0;
- f->bytes_in_seg = 0;
- return TRUE;
- }
- static int maybe_start_packet(vorb *f)
- {
- if (f->next_seg == -1) {
- int x = get8(f);
- if (f->eof) return FALSE;
- if (0x4f != x ) return error(f, VORBIS_missing_capture_pattern);
- if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern);
- if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern);
- if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern);
- if (!start_page_no_capturepattern(f)) return FALSE;
- if (f->page_flag & PAGEFLAG_continued_packet) {
- f->last_seg = FALSE;
- f->bytes_in_seg = 0;
- return error(f, VORBIS_continued_packet_flag_invalid);
- }
- }
- return start_packet(f);
- }
- static int next_segment(vorb *f)
- {
- int len;
- if (f->last_seg) return 0;
- if (f->next_seg == -1) {
- f->last_seg_which = f->segment_count-1;
- if (!start_page(f)) { f->last_seg = 1; return 0; }
- if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid);
- }
- len = f->segments[f->next_seg++];
- if (len < 255) {
- f->last_seg = TRUE;
- f->last_seg_which = f->next_seg-1;
- }
- if (f->next_seg >= f->segment_count)
- f->next_seg = -1;
- assert(f->bytes_in_seg == 0);
- f->bytes_in_seg = len;
- return len;
- }
- #define EOP (-1)
- #define INVALID_BITS (-1)
- static int get8_packet_raw(vorb *f)
- {
- if (!f->bytes_in_seg) {
- if (f->last_seg) return EOP;
- else if (!next_segment(f)) return EOP;
- }
- assert(f->bytes_in_seg > 0);
- --f->bytes_in_seg;
- ++f->packet_bytes;
- return get8(f);
- }
- static int get8_packet(vorb *f)
- {
- int x = get8_packet_raw(f);
- f->valid_bits = 0;
- return x;
- }
- static int get32_packet(vorb *f)
- {
- uint32 x;
- x = get8_packet(f);
- x += get8_packet(f) << 8;
- x += get8_packet(f) << 16;
- x += (uint32) get8_packet(f) << 24;
- return x;
- }
- static void flush_packet(vorb *f)
- {
- while (get8_packet_raw(f) != EOP);
- }
- static uint32 get_bits(vorb *f, int n)
- {
- uint32 z;
- if (f->valid_bits < 0) return 0;
- if (f->valid_bits < n) {
- if (n > 24) {
- z = get_bits(f, 24);
- z += get_bits(f, n-24) << 24;
- return z;
- }
- if (f->valid_bits == 0) f->acc = 0;
- while (f->valid_bits < n) {
- int z = get8_packet_raw(f);
- if (z == EOP) {
- f->valid_bits = INVALID_BITS;
- return 0;
- }
- f->acc += z << f->valid_bits;
- f->valid_bits += 8;
- }
- }
- assert(f->valid_bits >= n);
- z = f->acc & ((1 << n)-1);
- f->acc >>= n;
- f->valid_bits -= n;
- return z;
- }
- static __forceinline void prep_huffman(vorb *f)
- {
- if (f->valid_bits <= 24) {
- if (f->valid_bits == 0) f->acc = 0;
- do {
- int z;
- if (f->last_seg && !f->bytes_in_seg) return;
- z = get8_packet_raw(f);
- if (z == EOP) return;
- f->acc += (unsigned) z << f->valid_bits;
- f->valid_bits += 8;
- } while (f->valid_bits <= 24);
- }
- }
- enum
- {
- VORBIS_packet_id = 1,
- VORBIS_packet_comment = 3,
- VORBIS_packet_setup = 5
- };
- static int codebook_decode_scalar_raw(vorb *f, Codebook *c)
- {
- int i;
- prep_huffman(f);
- if (c->codewords == NULL && c->sorted_codewords == NULL)
- return -1;
- if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) {
- uint32 code = bit_reverse(f->acc);
- int x=0, n=c->sorted_entries, len;
- while (n > 1) {
- int m = x + (n >> 1);
- if (c->sorted_codewords[m] <= code) {
- x = m;
- n -= (n>>1);
- } else {
- n >>= 1;
- }
- }
- if (!c->sparse) x = c->sorted_values[x];
- len = c->codeword_lengths[x];
- if (f->valid_bits >= len) {
- f->acc >>= len;
- f->valid_bits -= len;
- return x;
- }
- f->valid_bits = 0;
- return -1;
- }
- assert(!c->sparse);
- for (i=0; i < c->entries; ++i) {
- if (c->codeword_lengths[i] == NO_CODE) continue;
- if (c->codewords[i] == (f->acc & ((1 << c->codeword_lengths[i])-1))) {
- if (f->valid_bits >= c->codeword_lengths[i]) {
- f->acc >>= c->codeword_lengths[i];
- f->valid_bits -= c->codeword_lengths[i];
- return i;
- }
- f->valid_bits = 0;
- return -1;
- }
- }
- error(f, VORBIS_invalid_stream);
- f->valid_bits = 0;
- return -1;
- }
- #ifndef STB_VORBIS_NO_INLINE_DECODE
- #define DECODE_RAW(var, f,c) \
- if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) \
- prep_huffman(f); \
- var = f->acc & FAST_HUFFMAN_TABLE_MASK; \
- var = c->fast_huffman[var]; \
- if (var >= 0) { \
- int n = c->codeword_lengths[var]; \
- f->acc >>= n; \
- f->valid_bits -= n; \
- if (f->valid_bits < 0) { f->valid_bits = 0; var = -1; } \
- } else { \
- var = codebook_decode_scalar_raw(f,c); \
- }
- #else
- static int codebook_decode_scalar(vorb *f, Codebook *c)
- {
- int i;
- if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH)
- prep_huffman(f);
- i = f->acc & FAST_HUFFMAN_TABLE_MASK;
- i = c->fast_huffman[i];
- if (i >= 0) {
- f->acc >>= c->codeword_lengths[i];
- f->valid_bits -= c->codeword_lengths[i];
- if (f->valid_bits < 0) { f->valid_bits = 0; return -1; }
- return i;
- }
- return codebook_decode_scalar_raw(f,c);
- }
- #define DECODE_RAW(var,f,c) var = codebook_decode_scalar(f,c);
- #endif
- #define DECODE(var,f,c) \
- DECODE_RAW(var,f,c) \
- if (c->sparse) var = c->sorted_values[var];
- #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
- #define DECODE_VQ(var,f,c) DECODE_RAW(var,f,c)
- #else
- #define DECODE_VQ(var,f,c) DECODE(var,f,c)
- #endif
- #define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off])
- #define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off])
- #define CODEBOOK_ELEMENT_BASE(c) (0)
- static int codebook_decode_start(vorb *f, Codebook *c)
- {
- int z = -1;
- if (c->lookup_type == 0)
- error(f, VORBIS_invalid_stream);
- else {
- DECODE_VQ(z,f,c);
- if (c->sparse) assert(z < c->sorted_entries);
- if (z < 0) {
- if (!f->bytes_in_seg)
- if (f->last_seg)
- return z;
- error(f, VORBIS_invalid_stream);
- }
- }
- return z;
- }
- static int codebook_decode(vorb *f, Codebook *c, float *output, int len)
- {
- int i,z = codebook_decode_start(f,c);
- if (z < 0) return FALSE;
- if (len > c->dimensions) len = c->dimensions;
- #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
- if (c->lookup_type == 1) {
- float last = CODEBOOK_ELEMENT_BASE(c);
- int div = 1;
- for (i=0; i < len; ++i) {
- int off = (z / div) % c->lookup_values;
- float val = CODEBOOK_ELEMENT_FAST(c,off) + last;
- output[i] += val;
- if (c->sequence_p) last = val + c->minimum_value;
- div *= c->lookup_values;
- }
- return TRUE;
- }
- #endif
- z *= c->dimensions;
- if (c->sequence_p) {
- float last = CODEBOOK_ELEMENT_BASE(c);
- for (i=0; i < len; ++i) {
- float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
- output[i] += val;
- last = val + c->minimum_value;
- }
- } else {
- float last = CODEBOOK_ELEMENT_BASE(c);
- for (i=0; i < len; ++i) {
- output[i] += CODEBOOK_ELEMENT_FAST(c,z+i) + last;
- }
- }
- return TRUE;
- }
- static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, int step)
- {
- int i,z = codebook_decode_start(f,c);
- float last = CODEBOOK_ELEMENT_BASE(c);
- if (z < 0) return FALSE;
- if (len > c->dimensions) len = c->dimensions;
- #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
- if (c->lookup_type == 1) {
- int div = 1;
- for (i=0; i < len; ++i) {
- int off = (z / div) % c->lookup_values;
- float val = CODEBOOK_ELEMENT_FAST(c,off) + last;
- output[i*step] += val;
- if (c->sequence_p) last = val;
- div *= c->lookup_values;
- }
- return TRUE;
- }
- #endif
- z *= c->dimensions;
- for (i=0; i < len; ++i) {
- float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
- output[i*step] += val;
- if (c->sequence_p) last = val;
- }
- return TRUE;
- }
- static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode)
- {
- int c_inter = *c_inter_p;
- int p_inter = *p_inter_p;
- int i,z, effective = c->dimensions;
- if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream);
- while (total_decode > 0) {
- float last = CODEBOOK_ELEMENT_BASE(c);
- DECODE_VQ(z,f,c);
- #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
- assert(!c->sparse || z < c->sorted_entries);
- #endif
- if (z < 0) {
- if (!f->bytes_in_seg)
- if (f->last_seg) return FALSE;
- return error(f, VORBIS_invalid_stream);
- }
- if (c_inter + p_inter*ch + effective > len * ch) {
- effective = len*ch - (p_inter*ch - c_inter);
- }
- #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
- if (c->lookup_type == 1) {
- int div = 1;
- for (i=0; i < effective; ++i) {
- int off = (z / div) % c->lookup_values;
- float val = CODEBOOK_ELEMENT_FAST(c,off) + last;
- if (outputs[c_inter])
- outputs[c_inter][p_inter] += val;
- if (++c_inter == ch) { c_inter = 0; ++p_inter; }
- if (c->sequence_p) last = val;
- div *= c->lookup_values;
- }
- } else
- #endif
- {
- z *= c->dimensions;
- if (c->sequence_p) {
- for (i=0; i < effective; ++i) {
- float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
- if (outputs[c_inter])
- outputs[c_inter][p_inter] += val;
- if (++c_inter == ch) { c_inter = 0; ++p_inter; }
- last = val;
- }
- } else {
- for (i=0; i < effective; ++i) {
- float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last;
- if (outputs[c_inter])
- outputs[c_inter][p_inter] += val;
- if (++c_inter == ch) { c_inter = 0; ++p_inter; }
- }
- }
- }
- total_decode -= effective;
- }
- *c_inter_p = c_inter;
- *p_inter_p = p_inter;
- return TRUE;
- }
- static int predict_point(int x, int x0, int x1, int y0, int y1)
- {
- int dy = y1 - y0;
- int adx = x1 - x0;
- int err = abs(dy) * (x - x0);
- int off = err / adx;
- return dy < 0 ? y0 - off : y0 + off;
- }
- static float inverse_db_table[256] =
- {
- 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f,
- 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f,
- 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f,
- 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f,
- 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f,
- 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f,
- 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f,
- 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f,
- 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f,
- 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f,
- 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f,
- 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f,
- 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f,
- 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f,
- 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f,
- 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f,
- 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f,
- 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f,
- 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f,
- 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f,
- 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f,
- 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f,
- 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f,
- 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f,
- 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f,
- 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f,
- 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f,
- 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f,
- 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f,
- 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f,
- 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f,
- 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f,
- 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f,
- 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f,
- 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f,
- 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f,
- 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f,
- 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f,
- 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f,
- 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f,
- 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f,
- 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f,
- 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f,
- 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f,
- 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f,
- 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f,
- 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f,
- 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f,
- 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f,
- 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f,
- 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f,
- 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f,
- 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f,
- 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f,
- 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f,
- 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f,
- 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f,
- 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f,
- 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f,
- 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f,
- 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f,
- 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f,
- 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f,
- 0.82788260f, 0.88168307f, 0.9389798f, 1.0f
- };
- #ifndef STB_VORBIS_NO_DEFER_FLOOR
- #define LINE_OP(a,b) a *= b
- #else
- #define LINE_OP(a,b) a = b
- #endif
- #ifdef STB_VORBIS_DIVIDE_TABLE
- #define DIVTAB_NUMER 32
- #define DIVTAB_DENOM 64
- int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM];
- #endif
- static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y1, int n)
- {
- int dy = y1 - y0;
- int adx = x1 - x0;
- int ady = abs(dy);
- int base;
- int x=x0,y=y0;
- int err = 0;
- int sy;
- #ifdef STB_VORBIS_DIVIDE_TABLE
- if (adx < DIVTAB_DENOM && ady < DIVTAB_NUMER) {
- if (dy < 0) {
- base = -integer_divide_table[ady][adx];
- sy = base-1;
- } else {
- base = integer_divide_table[ady][adx];
- sy = base+1;
- }
- } else {
- base = dy / adx;
- if (dy < 0)
- sy = base - 1;
- else
- sy = base+1;
- }
- #else
- base = dy / adx;
- if (dy < 0)
- sy = base - 1;
- else
- sy = base+1;
- #endif
- ady -= abs(base) * adx;
- if (x1 > n) x1 = n;
- if (x < x1) {
- LINE_OP(output[x], inverse_db_table[y&255]);
- for (++x; x < x1; ++x) {
- err += ady;
- if (err >= adx) {
- err -= adx;
- y += sy;
- } else
- y += base;
- LINE_OP(output[x], inverse_db_table[y&255]);
- }
- }
- }
- static int residue_decode(vorb *f, Codebook *book, float *target, int offset, int n, int rtype)
- {
- int k;
- if (rtype == 0) {
- int step = n / book->dimensions;
- for (k=0; k < step; ++k)
- if (!codebook_decode_step(f, book, target+offset+k, n-offset-k, step))
- return FALSE;
- } else {
- for (k=0; k < n; ) {
- if (!codebook_decode(f, book, target+offset, n-k))
- return FALSE;
- k += book->dimensions;
- offset += book->dimensions;
- }
- }
- return TRUE;
- }
- static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode)
- {
- int i,j,pass;
- Residue *r = f->residue_config + rn;
- int rtype = f->residue_types[rn];
- int c = r->classbook;
- int classwords = f->codebooks[c].dimensions;
- unsigned int actual_size = rtype == 2 ? n*2 : n;
- unsigned int limit_r_begin = (r->begin < actual_size ? r->begin : actual_size);
- unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size);
- int n_read = limit_r_end - limit_r_begin;
- int part_read = n_read / r->part_size;
- int temp_alloc_point = temp_alloc_save(f);
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- uint8 ***part_classdata = (uint8 ***) temp_block_array(f,f->channels, part_read * sizeof(**part_classdata));
- #else
- int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications));
- #endif
- CHECK(f);
- for (i=0; i < ch; ++i)
- if (!do_not_decode[i])
- memset(residue_buffers[i], 0, sizeof(float) * n);
- if (rtype == 2 && ch != 1) {
- for (j=0; j < ch; ++j)
- if (!do_not_decode[j])
- break;
- if (j == ch)
- goto done;
- for (pass=0; pass < 8; ++pass) {
- int pcount = 0, class_set = 0;
- if (ch == 2) {
- while (pcount < part_read) {
- int z = r->begin + pcount*r->part_size;
- int c_inter = (z & 1), p_inter = z>>1;
- if (pass == 0) {
- Codebook *c = f->codebooks+r->classbook;
- int q;
- DECODE(q,f,c);
- if (q == EOP) goto done;
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- part_classdata[0][class_set] = r->classdata[q];
- #else
- for (i=classwords-1; i >= 0; --i) {
- classifications[0][i+pcount] = q % r->classifications;
- q /= r->classifications;
- }
- #endif
- }
- for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
- int z = r->begin + pcount*r->part_size;
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- int c = part_classdata[0][class_set][i];
- #else
- int c = classifications[0][pcount];
- #endif
- int b = r->residue_books[c][pass];
- if (b >= 0) {
- Codebook *book = f->codebooks + b;
- #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK
- if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
- goto done;
- #else
- if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
- goto done;
- #endif
- } else {
- z += r->part_size;
- c_inter = z & 1;
- p_inter = z >> 1;
- }
- }
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- ++class_set;
- #endif
- }
- } else if (ch > 2) {
- while (pcount < part_read) {
- int z = r->begin + pcount*r->part_size;
- int c_inter = z % ch, p_inter = z/ch;
- if (pass == 0) {
- Codebook *c = f->codebooks+r->classbook;
- int q;
- DECODE(q,f,c);
- if (q == EOP) goto done;
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- part_classdata[0][class_set] = r->classdata[q];
- #else
- for (i=classwords-1; i >= 0; --i) {
- classifications[0][i+pcount] = q % r->classifications;
- q /= r->classifications;
- }
- #endif
- }
- for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
- int z = r->begin + pcount*r->part_size;
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- int c = part_classdata[0][class_set][i];
- #else
- int c = classifications[0][pcount];
- #endif
- int b = r->residue_books[c][pass];
- if (b >= 0) {
- Codebook *book = f->codebooks + b;
- if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size))
- goto done;
- } else {
- z += r->part_size;
- c_inter = z % ch;
- p_inter = z / ch;
- }
- }
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- ++class_set;
- #endif
- }
- }
- }
- goto done;
- }
- CHECK(f);
- for (pass=0; pass < 8; ++pass) {
- int pcount = 0, class_set=0;
- while (pcount < part_read) {
- if (pass == 0) {
- for (j=0; j < ch; ++j) {
- if (!do_not_decode[j]) {
- Codebook *c = f->codebooks+r->classbook;
- int temp;
- DECODE(temp,f,c);
- if (temp == EOP) goto done;
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- part_classdata[j][class_set] = r->classdata[temp];
- #else
- for (i=classwords-1; i >= 0; --i) {
- classifications[j][i+pcount] = temp % r->classifications;
- temp /= r->classifications;
- }
- #endif
- }
- }
- }
- for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) {
- for (j=0; j < ch; ++j) {
- if (!do_not_decode[j]) {
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- int c = part_classdata[j][class_set][i];
- #else
- int c = classifications[j][pcount];
- #endif
- int b = r->residue_books[c][pass];
- if (b >= 0) {
- float *target = residue_buffers[j];
- int offset = r->begin + pcount * r->part_size;
- int n = r->part_size;
- Codebook *book = f->codebooks + b;
- if (!residue_decode(f, book, target, offset, n, rtype))
- goto done;
- }
- }
- }
- }
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- ++class_set;
- #endif
- }
- }
- done:
- CHECK(f);
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- temp_free(f,part_classdata);
- #else
- temp_free(f,classifications);
- #endif
- temp_alloc_restore(f,temp_alloc_point);
- }
- #if 0
- void inverse_mdct_slow(float *buffer, int n)
- {
- int i,j;
- int n2 = n >> 1;
- float *x = (float *) malloc(sizeof(*x) * n2);
- memcpy(x, buffer, sizeof(*x) * n2);
- for (i=0; i < n; ++i) {
- float acc = 0;
- for (j=0; j < n2; ++j)
- acc += x[j] * (float) cos(M_PI / 2 / n * (2 * i + 1 + n/2.0)*(2*j+1));
- buffer[i] = acc;
- }
- free(x);
- }
- #elif 0
- void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype)
- {
- float mcos[16384];
- int i,j;
- int n2 = n >> 1, nmask = (n << 2) -1;
- float *x = (float *) malloc(sizeof(*x) * n2);
- memcpy(x, buffer, sizeof(*x) * n2);
- for (i=0; i < 4*n; ++i)
- mcos[i] = (float) cos(M_PI / 2 * i / n);
- for (i=0; i < n; ++i) {
- float acc = 0;
- for (j=0; j < n2; ++j)
- acc += x[j] * mcos[(2 * i + 1 + n2)*(2*j+1) & nmask];
- buffer[i] = acc;
- }
- free(x);
- }
- #elif 0
- void dct_iv_slow(float *buffer, int n)
- {
- float mcos[16384];
- float x[2048];
- int i,j;
- int n2 = n >> 1, nmask = (n << 3) - 1;
- memcpy(x, buffer, sizeof(*x) * n);
- for (i=0; i < 8*n; ++i)
- mcos[i] = (float) cos(M_PI / 4 * i / n);
- for (i=0; i < n; ++i) {
- float acc = 0;
- for (j=0; j < n; ++j)
- acc += x[j] * mcos[((2 * i + 1)*(2*j+1)) & nmask];
- buffer[i] = acc;
- }
- }
- void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype)
- {
- int i, n4 = n >> 2, n2 = n >> 1, n3_4 = n - n4;
- float temp[4096];
- memcpy(temp, buffer, n2 * sizeof(float));
- dct_iv_slow(temp, n2);
- for (i=0; i < n4 ; ++i) buffer[i] = temp[i+n4];
- for ( ; i < n3_4; ++i) buffer[i] = -temp[n3_4 - i - 1];
- for ( ; i < n ; ++i) buffer[i] = -temp[i - n3_4];
- }
- #endif
- #ifndef LIBVORBIS_MDCT
- #define LIBVORBIS_MDCT 0
- #endif
- #if LIBVORBIS_MDCT
- typedef struct
- {
- int n;
- int log2n;
- float *trig;
- int *bitrev;
- float scale;
- } mdct_lookup;
- extern void mdct_init(mdct_lookup *lookup, int n);
- extern void mdct_clear(mdct_lookup *l);
- extern void mdct_backward(mdct_lookup *init, float *in, float *out);
- mdct_lookup M1,M2;
- void inverse_mdct(float *buffer, int n, vorb *f, int blocktype)
- {
- mdct_lookup *M;
- if (M1.n == n) M = &M1;
- else if (M2.n == n) M = &M2;
- else if (M1.n == 0) { mdct_init(&M1, n); M = &M1; }
- else {
- if (M2.n) __asm int 3;
- mdct_init(&M2, n);
- M = &M2;
- }
- mdct_backward(M, buffer, buffer);
- }
- #endif
- static void imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A)
- {
- float *ee0 = e + i_off;
- float *ee2 = ee0 + k_off;
- int i;
- assert((n & 3) == 0);
- for (i=(n>>2); i > 0; --i) {
- float k00_20, k01_21;
- k00_20 = ee0[ 0] - ee2[ 0];
- k01_21 = ee0[-1] - ee2[-1];
- ee0[ 0] += ee2[ 0];
- ee0[-1] += ee2[-1];
- ee2[ 0] = k00_20 * A[0] - k01_21 * A[1];
- ee2[-1] = k01_21 * A[0] + k00_20 * A[1];
- A += 8;
- k00_20 = ee0[-2] - ee2[-2];
- k01_21 = ee0[-3] - ee2[-3];
- ee0[-2] += ee2[-2];
- ee0[-3] += ee2[-3];
- ee2[-2] = k00_20 * A[0] - k01_21 * A[1];
- ee2[-3] = k01_21 * A[0] + k00_20 * A[1];
- A += 8;
- k00_20 = ee0[-4] - ee2[-4];
- k01_21 = ee0[-5] - ee2[-5];
- ee0[-4] += ee2[-4];
- ee0[-5] += ee2[-5];
- ee2[-4] = k00_20 * A[0] - k01_21 * A[1];
- ee2[-5] = k01_21 * A[0] + k00_20 * A[1];
- A += 8;
- k00_20 = ee0[-6] - ee2[-6];
- k01_21 = ee0[-7] - ee2[-7];
- ee0[-6] += ee2[-6];
- ee0[-7] += ee2[-7];
- ee2[-6] = k00_20 * A[0] - k01_21 * A[1];
- ee2[-7] = k01_21 * A[0] + k00_20 * A[1];
- A += 8;
- ee0 -= 8;
- ee2 -= 8;
- }
- }
- static void imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1)
- {
- int i;
- float k00_20, k01_21;
- float *e0 = e + d0;
- float *e2 = e0 + k_off;
- for (i=lim >> 2; i > 0; --i) {
- k00_20 = e0[-0] - e2[-0];
- k01_21 = e0[-1] - e2[-1];
- e0[-0] += e2[-0];
- e0[-1] += e2[-1];
- e2[-0] = (k00_20)*A[0] - (k01_21) * A[1];
- e2[-1] = (k01_21)*A[0] + (k00_20) * A[1];
- A += k1;
- k00_20 = e0[-2] - e2[-2];
- k01_21 = e0[-3] - e2[-3];
- e0[-2] += e2[-2];
- e0[-3] += e2[-3];
- e2[-2] = (k00_20)*A[0] - (k01_21) * A[1];
- e2[-3] = (k01_21)*A[0] + (k00_20) * A[1];
- A += k1;
- k00_20 = e0[-4] - e2[-4];
- k01_21 = e0[-5] - e2[-5];
- e0[-4] += e2[-4];
- e0[-5] += e2[-5];
- e2[-4] = (k00_20)*A[0] - (k01_21) * A[1];
- e2[-5] = (k01_21)*A[0] + (k00_20) * A[1];
- A += k1;
- k00_20 = e0[-6] - e2[-6];
- k01_21 = e0[-7] - e2[-7];
- e0[-6] += e2[-6];
- e0[-7] += e2[-7];
- e2[-6] = (k00_20)*A[0] - (k01_21) * A[1];
- e2[-7] = (k01_21)*A[0] + (k00_20) * A[1];
- e0 -= 8;
- e2 -= 8;
- A += k1;
- }
- }
- static void imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0)
- {
- int i;
- float A0 = A[0];
- float A1 = A[0+1];
- float A2 = A[0+a_off];
- float A3 = A[0+a_off+1];
- float A4 = A[0+a_off*2+0];
- float A5 = A[0+a_off*2+1];
- float A6 = A[0+a_off*3+0];
- float A7 = A[0+a_off*3+1];
- float k00,k11;
- float *ee0 = e +i_off;
- float *ee2 = ee0+k_off;
- for (i=n; i > 0; --i) {
- k00 = ee0[ 0] - ee2[ 0];
- k11 = ee0[-1] - ee2[-1];
- ee0[ 0] = ee0[ 0] + ee2[ 0];
- ee0[-1] = ee0[-1] + ee2[-1];
- ee2[ 0] = (k00) * A0 - (k11) * A1;
- ee2[-1] = (k11) * A0 + (k00) * A1;
- k00 = ee0[-2] - ee2[-2];
- k11 = ee0[-3] - ee2[-3];
- ee0[-2] = ee0[-2] + ee2[-2];
- ee0[-3] = ee0[-3] + ee2[-3];
- ee2[-2] = (k00) * A2 - (k11) * A3;
- ee2[-3] = (k11) * A2 + (k00) * A3;
- k00 = ee0[-4] - ee2[-4];
- k11 = ee0[-5] - ee2[-5];
- ee0[-4] = ee0[-4] + ee2[-4];
- ee0[-5] = ee0[-5] + ee2[-5];
- ee2[-4] = (k00) * A4 - (k11) * A5;
- ee2[-5] = (k11) * A4 + (k00) * A5;
- k00 = ee0[-6] - ee2[-6];
- k11 = ee0[-7] - ee2[-7];
- ee0[-6] = ee0[-6] + ee2[-6];
- ee0[-7] = ee0[-7] + ee2[-7];
- ee2[-6] = (k00) * A6 - (k11) * A7;
- ee2[-7] = (k11) * A6 + (k00) * A7;
- ee0 -= k0;
- ee2 -= k0;
- }
- }
- static __forceinline void iter_54(float *z)
- {
- float k00,k11,k22,k33;
- float y0,y1,y2,y3;
- k00 = z[ 0] - z[-4];
- y0 = z[ 0] + z[-4];
- y2 = z[-2] + z[-6];
- k22 = z[-2] - z[-6];
- z[-0] = y0 + y2;
- z[-2] = y0 - y2;
- k33 = z[-3] - z[-7];
- z[-4] = k00 + k33;
- z[-6] = k00 - k33;
- k11 = z[-1] - z[-5];
- y1 = z[-1] + z[-5];
- y3 = z[-3] + z[-7];
- z[-1] = y1 + y3;
- z[-3] = y1 - y3;
- z[-5] = k11 - k22;
- z[-7] = k11 + k22;
- }
- static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n)
- {
- int a_off = base_n >> 3;
- float A2 = A[0+a_off];
- float *z = e + i_off;
- float *base = z - 16 * n;
- while (z > base) {
- float k00,k11;
- float l00,l11;
- k00 = z[-0] - z[ -8];
- k11 = z[-1] - z[ -9];
- l00 = z[-2] - z[-10];
- l11 = z[-3] - z[-11];
- z[ -0] = z[-0] + z[ -8];
- z[ -1] = z[-1] + z[ -9];
- z[ -2] = z[-2] + z[-10];
- z[ -3] = z[-3] + z[-11];
- z[ -8] = k00;
- z[ -9] = k11;
- z[-10] = (l00+l11) * A2;
- z[-11] = (l11-l00) * A2;
- k00 = z[ -4] - z[-12];
- k11 = z[ -5] - z[-13];
- l00 = z[ -6] - z[-14];
- l11 = z[ -7] - z[-15];
- z[ -4] = z[ -4] + z[-12];
- z[ -5] = z[ -5] + z[-13];
- z[ -6] = z[ -6] + z[-14];
- z[ -7] = z[ -7] + z[-15];
- z[-12] = k11;
- z[-13] = -k00;
- z[-14] = (l11-l00) * A2;
- z[-15] = (l00+l11) * -A2;
- iter_54(z);
- iter_54(z-8);
- z -= 16;
- }
- }
- static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype)
- {
- int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l;
- int ld;
- int save_point = temp_alloc_save(f);
- float *buf2 = (float *) temp_alloc(f, n2 * sizeof(*buf2));
- float *u=NULL,*v=NULL;
- float *A = f->A[blocktype];
- {
- float *d,*e, *AA, *e_stop;
- d = &buf2[n2-2];
- AA = A;
- e = &buffer[0];
- e_stop = &buffer[n2];
- while (e != e_stop) {
- d[1] = (e[0] * AA[0] - e[2]*AA[1]);
- d[0] = (e[0] * AA[1] + e[2]*AA[0]);
- d -= 2;
- AA += 2;
- e += 4;
- }
- e = &buffer[n2-3];
- while (d >= buf2) {
- d[1] = (-e[2] * AA[0] - -e[0]*AA[1]);
- d[0] = (-e[2] * AA[1] + -e[0]*AA[0]);
- d -= 2;
- AA += 2;
- e -= 4;
- }
- }
- u = buffer;
- v = buf2;
- {
- float *AA = &A[n2-8];
- float *d0,*d1, *e0, *e1;
- e0 = &v[n4];
- e1 = &v[0];
- d0 = &u[n4];
- d1 = &u[0];
- while (AA >= A) {
- float v40_20, v41_21;
- v41_21 = e0[1] - e1[1];
- v40_20 = e0[0] - e1[0];
- d0[1] = e0[1] + e1[1];
- d0[0] = e0[0] + e1[0];
- d1[1] = v41_21*AA[4] - v40_20*AA[5];
- d1[0] = v40_20*AA[4] + v41_21*AA[5];
- v41_21 = e0[3] - e1[3];
- v40_20 = e0[2] - e1[2];
- d0[3] = e0[3] + e1[3];
- d0[2] = e0[2] + e1[2];
- d1[3] = v41_21*AA[0] - v40_20*AA[1];
- d1[2] = v40_20*AA[0] + v41_21*AA[1];
- AA -= 8;
- d0 += 4;
- d1 += 4;
- e0 += 4;
- e1 += 4;
- }
- }
- ld = ilog(n) - 1;
- imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A);
- imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A);
- imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16);
- imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16);
- imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16);
- imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16);
- l=2;
- for (; l < (ld-3)>>1; ++l) {
- int k0 = n >> (l+2), k0_2 = k0>>1;
- int lim = 1 << (l+1);
- int i;
- for (i=0; i < lim; ++i)
- imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3));
- }
- for (; l < ld-6; ++l) {
- int k0 = n >> (l+2), k1 = 1 << (l+3), k0_2 = k0>>1;
- int rlim = n >> (l+6), r;
- int lim = 1 << (l+1);
- int i_off;
- float *A0 = A;
- i_off = n2-1;
- for (r=rlim; r > 0; --r) {
- imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0);
- A0 += k1*4;
- i_off -= 8;
- }
- }
- imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n);
- {
- uint16 *bitrev = f->bit_reverse[blocktype];
- float *d0 = &v[n4-4];
- float *d1 = &v[n2-4];
- while (d0 >= v) {
- int k4;
- k4 = bitrev[0];
- d1[3] = u[k4+0];
- d1[2] = u[k4+1];
- d0[3] = u[k4+2];
- d0[2] = u[k4+3];
- k4 = bitrev[1];
- d1[1] = u[k4+0];
- d1[0] = u[k4+1];
- d0[1] = u[k4+2];
- d0[0] = u[k4+3];
- d0 -= 4;
- d1 -= 4;
- bitrev += 2;
- }
- }
- assert(v == buf2);
- {
- float *C = f->C[blocktype];
- float *d, *e;
- d = v;
- e = v + n2 - 4;
- while (d < e) {
- float a02,a11,b0,b1,b2,b3;
- a02 = d[0] - e[2];
- a11 = d[1] + e[3];
- b0 = C[1]*a02 + C[0]*a11;
- b1 = C[1]*a11 - C[0]*a02;
- b2 = d[0] + e[ 2];
- b3 = d[1] - e[ 3];
- d[0] = b2 + b0;
- d[1] = b3 + b1;
- e[2] = b2 - b0;
- e[3] = b1 - b3;
- a02 = d[2] - e[0];
- a11 = d[3] + e[1];
- b0 = C[3]*a02 + C[2]*a11;
- b1 = C[3]*a11 - C[2]*a02;
- b2 = d[2] + e[ 0];
- b3 = d[3] - e[ 1];
- d[2] = b2 + b0;
- d[3] = b3 + b1;
- e[0] = b2 - b0;
- e[1] = b1 - b3;
- C += 4;
- d += 4;
- e -= 4;
- }
- }
- {
- float *d0,*d1,*d2,*d3;
- float *B = f->B[blocktype] + n2 - 8;
- float *e = buf2 + n2 - 8;
- d0 = &buffer[0];
- d1 = &buffer[n2-4];
- d2 = &buffer[n2];
- d3 = &buffer[n-4];
- while (e >= v) {
- float p0,p1,p2,p3;
- p3 = e[6]*B[7] - e[7]*B[6];
- p2 = -e[6]*B[6] - e[7]*B[7];
- d0[0] = p3;
- d1[3] = - p3;
- d2[0] = p2;
- d3[3] = p2;
- p1 = e[4]*B[5] - e[5]*B[4];
- p0 = -e[4]*B[4] - e[5]*B[5];
- d0[1] = p1;
- d1[2] = - p1;
- d2[1] = p0;
- d3[2] = p0;
- p3 = e[2]*B[3] - e[3]*B[2];
- p2 = -e[2]*B[2] - e[3]*B[3];
- d0[2] = p3;
- d1[1] = - p3;
- d2[2] = p2;
- d3[1] = p2;
- p1 = e[0]*B[1] - e[1]*B[0];
- p0 = -e[0]*B[0] - e[1]*B[1];
- d0[3] = p1;
- d1[0] = - p1;
- d2[3] = p0;
- d3[0] = p0;
- B -= 8;
- e -= 8;
- d0 += 4;
- d2 += 4;
- d1 -= 4;
- d3 -= 4;
- }
- }
- temp_free(f,buf2);
- temp_alloc_restore(f,save_point);
- }
- #if 0
- void inverse_mdct_naive(float *buffer, int n)
- {
- float s;
- float A[1 << 12], B[1 << 12], C[1 << 11];
- int i,k,k2,k4, n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l;
- int n3_4 = n - n4, ld;
- float u[1 << 13], X[1 << 13], v[1 << 13], w[1 << 13];
- for (k=k2=0; k < n4; ++k,k2+=2) {
- A[k2 ] = (float) cos(4*k*M_PI/n);
- A[k2+1] = (float) -sin(4*k*M_PI/n);
- B[k2 ] = (float) cos((k2+1)*M_PI/n/2);
- B[k2+1] = (float) sin((k2+1)*M_PI/n/2);
- }
- for (k=k2=0; k < n8; ++k,k2+=2) {
- C[k2 ] = (float) cos(2*(k2+1)*M_PI/n);
- C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n);
- }
- for (k=0; k < n2; ++k) u[k] = buffer[k];
- for ( ; k < n ; ++k) u[k] = -buffer[n - k - 1];
- for (k=k2=k4=0; k < n4; k+=1, k2+=2, k4+=4) {
- v[n-k4-1] = (u[k4] - u[n-k4-1]) * A[k2] - (u[k4+2] - u[n-k4-3])*A[k2+1];
- v[n-k4-3] = (u[k4] - u[n-k4-1]) * A[k2+1] + (u[k4+2] - u[n-k4-3])*A[k2];
- }
- for (k=k4=0; k < n8; k+=1, k4+=4) {
- w[n2+3+k4] = v[n2+3+k4] + v[k4+3];
- w[n2+1+k4] = v[n2+1+k4] + v[k4+1];
- w[k4+3] = (v[n2+3+k4] - v[k4+3])*A[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*A[n2-3-k4];
- w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4];
- }
- ld = ilog(n) - 1;
- for (l=0; l < ld-3; ++l) {
- int k0 = n >> (l+2), k1 = 1 << (l+3);
- int rlim = n >> (l+4), r4, r;
- int s2lim = 1 << (l+2), s2;
- for (r=r4=0; r < rlim; r4+=4,++r) {
- for (s2=0; s2 < s2lim; s2+=2) {
- u[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4];
- u[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4];
- u[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1]
- - (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1+1];
- u[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1]
- + (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1+1];
- }
- }
- if (l+1 < ld-3) {
- memcpy(w, u, sizeof(u));
- }
- }
- for (i=0; i < n8; ++i) {
- int j = bit_reverse(i) >> (32-ld+3);
- assert(j < n8);
- if (i == j) {
- int i8 = i << 3;
- v[i8+1] = u[i8+1];
- v[i8+3] = u[i8+3];
- v[i8+5] = u[i8+5];
- v[i8+7] = u[i8+7];
- } else if (i < j) {
- int i8 = i << 3, j8 = j << 3;
- v[j8+1] = u[i8+1], v[i8+1] = u[j8 + 1];
- v[j8+3] = u[i8+3], v[i8+3] = u[j8 + 3];
- v[j8+5] = u[i8+5], v[i8+5] = u[j8 + 5];
- v[j8+7] = u[i8+7], v[i8+7] = u[j8 + 7];
- }
- }
- for (k=0; k < n2; ++k) {
- w[k] = v[k*2+1];
- }
- for (k=k2=k4=0; k < n8; ++k, k2 += 2, k4 += 4) {
- u[n-1-k2] = w[k4];
- u[n-2-k2] = w[k4+1];
- u[n3_4 - 1 - k2] = w[k4+2];
- u[n3_4 - 2 - k2] = w[k4+3];
- }
- for (k=k2=0; k < n8; ++k, k2 += 2) {
- v[n2 + k2 ] = ( u[n2 + k2] + u[n-2-k2] + C[k2+1]*(u[n2+k2]-u[n-2-k2]) + C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
- v[n-2 - k2] = ( u[n2 + k2] + u[n-2-k2] - C[k2+1]*(u[n2+k2]-u[n-2-k2]) - C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2;
- v[n2+1+ k2] = ( u[n2+1+k2] - u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
- v[n-1 - k2] = (-u[n2+1+k2] + u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2;
- }
- for (k=k2=0; k < n4; ++k,k2 += 2) {
- X[k] = v[k2+n2]*B[k2 ] + v[k2+1+n2]*B[k2+1];
- X[n2-1-k] = v[k2+n2]*B[k2+1] - v[k2+1+n2]*B[k2 ];
- }
- s = 0.5;
- for (i=0; i < n4 ; ++i) buffer[i] = s * X[i+n4];
- for ( ; i < n3_4; ++i) buffer[i] = -s * X[n3_4 - i - 1];
- for ( ; i < n ; ++i) buffer[i] = -s * X[i - n3_4];
- }
- #endif
- static float *get_window(vorb *f, int len)
- {
- len <<= 1;
- if (len == f->blocksize_0) return f->window[0];
- if (len == f->blocksize_1) return f->window[1];
- return NULL;
- }
- #ifndef STB_VORBIS_NO_DEFER_FLOOR
- typedef int16 YTYPE;
- #else
- typedef int YTYPE;
- #endif
- static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *finalY, uint8 *step2_flag)
- {
- int n2 = n >> 1;
- int s = map->chan[i].mux, floor;
- floor = map->submap_floor[s];
- if (f->floor_types[floor] == 0) {
- return error(f, VORBIS_invalid_stream);
- } else {
- Floor1 *g = &f->floor_config[floor].floor1;
- int j,q;
- int lx = 0, ly = finalY[0] * g->floor1_multiplier;
- for (q=1; q < g->values; ++q) {
- j = g->sorted_order[q];
- #ifndef STB_VORBIS_NO_DEFER_FLOOR
- STBV_NOTUSED(step2_flag);
- if (finalY[j] >= 0)
- #else
- if (step2_flag[j])
- #endif
- {
- int hy = finalY[j] * g->floor1_multiplier;
- int hx = g->Xlist[j];
- if (lx != hx)
- draw_line(target, lx,ly, hx,hy, n2);
- CHECK(f);
- lx = hx, ly = hy;
- }
- }
- if (lx < n2) {
- for (j=lx; j < n2; ++j)
- LINE_OP(target[j], inverse_db_table[ly]);
- CHECK(f);
- }
- }
- return TRUE;
- }
- static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode)
- {
- Mode *m;
- int i, n, prev, next, window_center;
- f->channel_buffer_start = f->channel_buffer_end = 0;
- retry:
- if (f->eof) return FALSE;
- if (!maybe_start_packet(f))
- return FALSE;
- if (get_bits(f,1) != 0) {
- if (IS_PUSH_MODE(f))
- return error(f,VORBIS_bad_packet_type);
- while (EOP != get8_packet(f));
- goto retry;
- }
- if (f->alloc.alloc_buffer)
- assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
- i = get_bits(f, ilog(f->mode_count-1));
- if (i == EOP) return FALSE;
- if (i >= f->mode_count) return FALSE;
- *mode = i;
- m = f->mode_config + i;
- if (m->blockflag) {
- n = f->blocksize_1;
- prev = get_bits(f,1);
- next = get_bits(f,1);
- } else {
- prev = next = 0;
- n = f->blocksize_0;
- }
- window_center = n >> 1;
- if (m->blockflag && !prev) {
- *p_left_start = (n - f->blocksize_0) >> 2;
- *p_left_end = (n + f->blocksize_0) >> 2;
- } else {
- *p_left_start = 0;
- *p_left_end = window_center;
- }
- if (m->blockflag && !next) {
- *p_right_start = (n*3 - f->blocksize_0) >> 2;
- *p_right_end = (n*3 + f->blocksize_0) >> 2;
- } else {
- *p_right_start = window_center;
- *p_right_end = n;
- }
- return TRUE;
- }
- static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, int left_end, int right_start, int right_end, int *p_left)
- {
- Mapping *map;
- int i,j,k,n,n2;
- int zero_channel[256];
- int really_zero_channel[256];
- STBV_NOTUSED(left_end);
- n = f->blocksize[m->blockflag];
- map = &f->mapping[m->mapping];
- n2 = n >> 1;
- CHECK(f);
- for (i=0; i < f->channels; ++i) {
- int s = map->chan[i].mux, floor;
- zero_channel[i] = FALSE;
- floor = map->submap_floor[s];
- if (f->floor_types[floor] == 0) {
- return error(f, VORBIS_invalid_stream);
- } else {
- Floor1 *g = &f->floor_config[floor].floor1;
- if (get_bits(f, 1)) {
- short *finalY;
- uint8 step2_flag[256];
- static int range_list[4] = { 256, 128, 86, 64 };
- int range = range_list[g->floor1_multiplier-1];
- int offset = 2;
- finalY = f->finalY[i];
- finalY[0] = get_bits(f, ilog(range)-1);
- finalY[1] = get_bits(f, ilog(range)-1);
- for (j=0; j < g->partitions; ++j) {
- int pclass = g->partition_class_list[j];
- int cdim = g->class_dimensions[pclass];
- int cbits = g->class_subclasses[pclass];
- int csub = (1 << cbits)-1;
- int cval = 0;
- if (cbits) {
- Codebook *c = f->codebooks + g->class_masterbooks[pclass];
- DECODE(cval,f,c);
- }
- for (k=0; k < cdim; ++k) {
- int book = g->subclass_books[pclass][cval & csub];
- cval = cval >> cbits;
- if (book >= 0) {
- int temp;
- Codebook *c = f->codebooks + book;
- DECODE(temp,f,c);
- finalY[offset++] = temp;
- } else
- finalY[offset++] = 0;
- }
- }
- if (f->valid_bits == INVALID_BITS) goto error;
- step2_flag[0] = step2_flag[1] = 1;
- for (j=2; j < g->values; ++j) {
- int low, high, pred, highroom, lowroom, room, val;
- low = g->neighbors[j][0];
- high = g->neighbors[j][1];
- pred = predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]);
- val = finalY[j];
- highroom = range - pred;
- lowroom = pred;
- if (highroom < lowroom)
- room = highroom * 2;
- else
- room = lowroom * 2;
- if (val) {
- step2_flag[low] = step2_flag[high] = 1;
- step2_flag[j] = 1;
- if (val >= room)
- if (highroom > lowroom)
- finalY[j] = val - lowroom + pred;
- else
- finalY[j] = pred - val + highroom - 1;
- else
- if (val & 1)
- finalY[j] = pred - ((val+1)>>1);
- else
- finalY[j] = pred + (val>>1);
- } else {
- step2_flag[j] = 0;
- finalY[j] = pred;
- }
- }
- #ifdef STB_VORBIS_NO_DEFER_FLOOR
- do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag);
- #else
- for (j=0; j < g->values; ++j) {
- if (!step2_flag[j])
- finalY[j] = -1;
- }
- #endif
- } else {
- error:
- zero_channel[i] = TRUE;
- }
- }
- }
- CHECK(f);
- if (f->alloc.alloc_buffer)
- assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
- memcpy(really_zero_channel, zero_channel, sizeof(really_zero_channel[0]) * f->channels);
- for (i=0; i < map->coupling_steps; ++i)
- if (!zero_channel[map->chan[i].magnitude] || !zero_channel[map->chan[i].angle]) {
- zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE;
- }
- CHECK(f);
- for (i=0; i < map->submaps; ++i) {
- float *residue_buffers[STB_VORBIS_MAX_CHANNELS];
- int r;
- uint8 do_not_decode[256];
- int ch = 0;
- for (j=0; j < f->channels; ++j) {
- if (map->chan[j].mux == i) {
- if (zero_channel[j]) {
- do_not_decode[ch] = TRUE;
- residue_buffers[ch] = NULL;
- } else {
- do_not_decode[ch] = FALSE;
- residue_buffers[ch] = f->channel_buffers[j];
- }
- ++ch;
- }
- }
- r = map->submap_residue[i];
- decode_residue(f, residue_buffers, ch, n2, r, do_not_decode);
- }
- if (f->alloc.alloc_buffer)
- assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
- CHECK(f);
- for (i = map->coupling_steps-1; i >= 0; --i) {
- int n2 = n >> 1;
- float *m = f->channel_buffers[map->chan[i].magnitude];
- float *a = f->channel_buffers[map->chan[i].angle ];
- for (j=0; j < n2; ++j) {
- float a2,m2;
- if (m[j] > 0)
- if (a[j] > 0)
- m2 = m[j], a2 = m[j] - a[j];
- else
- a2 = m[j], m2 = m[j] + a[j];
- else
- if (a[j] > 0)
- m2 = m[j], a2 = m[j] + a[j];
- else
- a2 = m[j], m2 = m[j] - a[j];
- m[j] = m2;
- a[j] = a2;
- }
- }
- CHECK(f);
- #ifndef STB_VORBIS_NO_DEFER_FLOOR
- for (i=0; i < f->channels; ++i) {
- if (really_zero_channel[i]) {
- memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2);
- } else {
- do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL);
- }
- }
- #else
- for (i=0; i < f->channels; ++i) {
- if (really_zero_channel[i]) {
- memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2);
- } else {
- for (j=0; j < n2; ++j)
- f->channel_buffers[i][j] *= f->floor_buffers[i][j];
- }
- }
- #endif
- CHECK(f);
- for (i=0; i < f->channels; ++i)
- inverse_mdct(f->channel_buffers[i], n, f, m->blockflag);
- CHECK(f);
- flush_packet(f);
- if (f->first_decode) {
- f->current_loc = 0u - n2;
- f->discard_samples_deferred = n - right_end;
- f->current_loc_valid = TRUE;
- f->first_decode = FALSE;
- } else if (f->discard_samples_deferred) {
- if (f->discard_samples_deferred >= right_start - left_start) {
- f->discard_samples_deferred -= (right_start - left_start);
- left_start = right_start;
- *p_left = left_start;
- } else {
- left_start += f->discard_samples_deferred;
- *p_left = left_start;
- f->discard_samples_deferred = 0;
- }
- } else if (f->previous_length == 0 && f->current_loc_valid) {
- }
- if (f->last_seg_which == f->end_seg_with_known_loc) {
- if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) {
- uint32 current_end = f->known_loc_for_packet;
- if (current_end < f->current_loc + (right_end-left_start)) {
- if (current_end < f->current_loc) {
- *len = 0;
- } else {
- *len = current_end - f->current_loc;
- }
- *len += left_start;
- if (*len > right_end) *len = right_end;
- f->current_loc += *len;
- return TRUE;
- }
- }
- f->current_loc = f->known_loc_for_packet - (n2-left_start);
- f->current_loc_valid = TRUE;
- }
- if (f->current_loc_valid)
- f->current_loc += (right_start - left_start);
- if (f->alloc.alloc_buffer)
- assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset);
- *len = right_end;
- CHECK(f);
- return TRUE;
- }
- static int vorbis_decode_packet(vorb *f, int *len, int *p_left, int *p_right)
- {
- int mode, left_end, right_end;
- if (!vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0;
- return vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left);
- }
- static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right)
- {
- int prev,i,j;
- if (f->previous_length) {
- int i,j, n = f->previous_length;
- float *w = get_window(f, n);
- if (w == NULL) return 0;
- for (i=0; i < f->channels; ++i) {
- for (j=0; j < n; ++j)
- f->channel_buffers[i][left+j] =
- f->channel_buffers[i][left+j]*w[ j] +
- f->previous_window[i][ j]*w[n-1-j];
- }
- }
- prev = f->previous_length;
- f->previous_length = len - right;
- for (i=0; i < f->channels; ++i)
- for (j=0; right+j < len; ++j)
- f->previous_window[i][j] = f->channel_buffers[i][right+j];
- if (!prev)
- return 0;
- if (len < right) right = len;
- f->samples_output += right-left;
- return right - left;
- }
- static int vorbis_pump_first_frame(stb_vorbis *f)
- {
- int len, right, left, res;
- res = vorbis_decode_packet(f, &len, &left, &right);
- if (res)
- vorbis_finish_frame(f, len, left, right);
- return res;
- }
- static int start_decoder(vorb *f)
- {
- uint8 header[6], x,y;
- int len,i,j,k, max_submaps = 0;
- int longest_floorlist=0;
- f->first_decode = TRUE;
- if (!start_page(f)) return FALSE;
- if (!(f->page_flag & PAGEFLAG_first_page)) return error(f, VORBIS_invalid_first_page);
- if (f->page_flag & PAGEFLAG_last_page) return error(f, VORBIS_invalid_first_page);
- if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page);
- if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page);
- if (f->segments[0] != 30) {
- if (f->segments[0] == 64 &&
- getn(f, header, 6) &&
- header[0] == 'f' &&
- header[1] == 'i' &&
- header[2] == 's' &&
- header[3] == 'h' &&
- header[4] == 'e' &&
- header[5] == 'a' &&
- get8(f) == 'd' &&
- get8(f) == '\0') return error(f, VORBIS_ogg_skeleton_not_supported);
- else
- return error(f, VORBIS_invalid_first_page);
- }
- if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page);
- if (!getn(f, header, 6)) return error(f, VORBIS_unexpected_eof);
- if (!vorbis_validate(header)) return error(f, VORBIS_invalid_first_page);
- if (get32(f) != 0) return error(f, VORBIS_invalid_first_page);
- f->channels = get8(f); if (!f->channels) return error(f, VORBIS_invalid_first_page);
- if (f->channels > STB_VORBIS_MAX_CHANNELS) return error(f, VORBIS_too_many_channels);
- f->sample_rate = get32(f); if (!f->sample_rate) return error(f, VORBIS_invalid_first_page);
- get32(f);
- get32(f);
- get32(f);
- x = get8(f);
- {
- int log0,log1;
- log0 = x & 15;
- log1 = x >> 4;
- f->blocksize_0 = 1 << log0;
- f->blocksize_1 = 1 << log1;
- if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup);
- if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup);
- if (log0 > log1) return error(f, VORBIS_invalid_setup);
- }
- x = get8(f);
- if (!(x & 1)) return error(f, VORBIS_invalid_first_page);
- if (!start_page(f)) return FALSE;
- if (!start_packet(f)) return FALSE;
- if (!next_segment(f)) return FALSE;
- if (get8_packet(f) != VORBIS_packet_comment) return error(f, VORBIS_invalid_setup);
- for (i=0; i < 6; ++i) header[i] = get8_packet(f);
- if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup);
- len = get32_packet(f);
- f->vendor = (char*)setup_malloc(f, sizeof(char) * (len+1));
- if (f->vendor == NULL) return error(f, VORBIS_outofmem);
- for(i=0; i < len; ++i) {
- f->vendor[i] = get8_packet(f);
- }
- f->vendor[len] = (char)'\0';
- f->comment_list_length = get32_packet(f);
- f->comment_list = NULL;
- if (f->comment_list_length > 0)
- {
- f->comment_list = (char**) setup_malloc(f, sizeof(char*) * (f->comment_list_length));
- if (f->comment_list == NULL) return error(f, VORBIS_outofmem);
- }
- for(i=0; i < f->comment_list_length; ++i) {
- len = get32_packet(f);
- f->comment_list[i] = (char*)setup_malloc(f, sizeof(char) * (len+1));
- if (f->comment_list[i] == NULL) return error(f, VORBIS_outofmem);
- for(j=0; j < len; ++j) {
- f->comment_list[i][j] = get8_packet(f);
- }
- f->comment_list[i][len] = (char)'\0';
- }
- x = get8_packet(f);
- if (!(x & 1)) return error(f, VORBIS_invalid_setup);
- skip(f, f->bytes_in_seg);
- f->bytes_in_seg = 0;
- do {
- len = next_segment(f);
- skip(f, len);
- f->bytes_in_seg = 0;
- } while (len);
- if (!start_packet(f)) return FALSE;
- crc32_init();
- if (get8_packet(f) != VORBIS_packet_setup) return error(f, VORBIS_invalid_setup);
- for (i=0; i < 6; ++i) header[i] = get8_packet(f);
- if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup);
- f->codebook_count = get_bits(f,8) + 1;
- f->codebooks = (Codebook *) setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count);
- if (f->codebooks == NULL) return error(f, VORBIS_outofmem);
- memset(f->codebooks, 0, sizeof(*f->codebooks) * f->codebook_count);
- for (i=0; i < f->codebook_count; ++i) {
- uint32 *values;
- int ordered, sorted_count;
- int total=0;
- uint8 *lengths;
- Codebook *c = f->codebooks+i;
- CHECK(f);
- x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup);
- x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup);
- x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup);
- x = get_bits(f, 8);
- c->dimensions = (get_bits(f, 8)<<8) + x;
- x = get_bits(f, 8);
- y = get_bits(f, 8);
- c->entries = (get_bits(f, 8)<<16) + (y<<8) + x;
- ordered = get_bits(f,1);
- c->sparse = ordered ? 0 : get_bits(f,1);
- if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup);
- if (c->sparse)
- lengths = (uint8 *) setup_temp_malloc(f, c->entries);
- else
- lengths = c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries);
- if (!lengths) return error(f, VORBIS_outofmem);
- if (ordered) {
- int current_entry = 0;
- int current_length = get_bits(f,5) + 1;
- while (current_entry < c->entries) {
- int limit = c->entries - current_entry;
- int n = get_bits(f, ilog(limit));
- if (current_length >= 32) return error(f, VORBIS_invalid_setup);
- if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); }
- memset(lengths + current_entry, current_length, n);
- current_entry += n;
- ++current_length;
- }
- } else {
- for (j=0; j < c->entries; ++j) {
- int present = c->sparse ? get_bits(f,1) : 1;
- if (present) {
- lengths[j] = get_bits(f, 5) + 1;
- ++total;
- if (lengths[j] == 32)
- return error(f, VORBIS_invalid_setup);
- } else {
- lengths[j] = NO_CODE;
- }
- }
- }
- if (c->sparse && total >= c->entries >> 2) {
- if (c->entries > (int) f->setup_temp_memory_required)
- f->setup_temp_memory_required = c->entries;
- c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries);
- if (c->codeword_lengths == NULL) return error(f, VORBIS_outofmem);
- memcpy(c->codeword_lengths, lengths, c->entries);
- setup_temp_free(f, lengths, c->entries);
- lengths = c->codeword_lengths;
- c->sparse = 0;
- }
- if (c->sparse) {
- sorted_count = total;
- } else {
- sorted_count = 0;
- #ifndef STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH
- for (j=0; j < c->entries; ++j)
- if (lengths[j] > STB_VORBIS_FAST_HUFFMAN_LENGTH && lengths[j] != NO_CODE)
- ++sorted_count;
- #endif
- }
- c->sorted_entries = sorted_count;
- values = NULL;
- CHECK(f);
- if (!c->sparse) {
- c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries);
- if (!c->codewords) return error(f, VORBIS_outofmem);
- } else {
- unsigned int size;
- if (c->sorted_entries) {
- c->codeword_lengths = (uint8 *) setup_malloc(f, c->sorted_entries);
- if (!c->codeword_lengths) return error(f, VORBIS_outofmem);
- c->codewords = (uint32 *) setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries);
- if (!c->codewords) return error(f, VORBIS_outofmem);
- values = (uint32 *) setup_temp_malloc(f, sizeof(*values) * c->sorted_entries);
- if (!values) return error(f, VORBIS_outofmem);
- }
- size = c->entries + (sizeof(*c->codewords) + sizeof(*values)) * c->sorted_entries;
- if (size > f->setup_temp_memory_required)
- f->setup_temp_memory_required = size;
- }
- if (!compute_codewords(c, lengths, c->entries, values)) {
- if (c->sparse) setup_temp_free(f, values, 0);
- return error(f, VORBIS_invalid_setup);
- }
- if (c->sorted_entries) {
- c->sorted_codewords = (uint32 *) setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1));
- if (c->sorted_codewords == NULL) return error(f, VORBIS_outofmem);
- c->sorted_values = ( int *) setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1));
- if (c->sorted_values == NULL) return error(f, VORBIS_outofmem);
- ++c->sorted_values;
- c->sorted_values[-1] = -1;
- compute_sorted_huffman(c, lengths, values);
- }
- if (c->sparse) {
- setup_temp_free(f, values, sizeof(*values)*c->sorted_entries);
- setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries);
- setup_temp_free(f, lengths, c->entries);
- c->codewords = NULL;
- }
- compute_accelerated_huffman(c);
- CHECK(f);
- c->lookup_type = get_bits(f, 4);
- if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup);
- if (c->lookup_type > 0) {
- uint16 *mults;
- c->minimum_value = float32_unpack(get_bits(f, 32));
- c->delta_value = float32_unpack(get_bits(f, 32));
- c->value_bits = get_bits(f, 4)+1;
- c->sequence_p = get_bits(f,1);
- if (c->lookup_type == 1) {
- int values = lookup1_values(c->entries, c->dimensions);
- if (values < 0) return error(f, VORBIS_invalid_setup);
- c->lookup_values = (uint32) values;
- } else {
- c->lookup_values = c->entries * c->dimensions;
- }
- if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup);
- mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values);
- if (mults == NULL) return error(f, VORBIS_outofmem);
- for (j=0; j < (int) c->lookup_values; ++j) {
- int q = get_bits(f, c->value_bits);
- if (q == EOP) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_invalid_setup); }
- mults[j] = q;
- }
- #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
- if (c->lookup_type == 1) {
- int len, sparse = c->sparse;
- float last=0;
- if (sparse) {
- if (c->sorted_entries == 0) goto skip;
- c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions);
- } else
- c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions);
- if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
- len = sparse ? c->sorted_entries : c->entries;
- for (j=0; j < len; ++j) {
- unsigned int z = sparse ? c->sorted_values[j] : j;
- unsigned int div=1;
- for (k=0; k < c->dimensions; ++k) {
- int off = (z / div) % c->lookup_values;
- float val = mults[off]*c->delta_value + c->minimum_value + last;
- c->multiplicands[j*c->dimensions + k] = val;
- if (c->sequence_p)
- last = val;
- if (k+1 < c->dimensions) {
- if (div > UINT_MAX / (unsigned int) c->lookup_values) {
- setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values);
- return error(f, VORBIS_invalid_setup);
- }
- div *= c->lookup_values;
- }
- }
- }
- c->lookup_type = 2;
- }
- else
- #endif
- {
- float last=0;
- CHECK(f);
- c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values);
- if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); }
- for (j=0; j < (int) c->lookup_values; ++j) {
- float val = mults[j] * c->delta_value + c->minimum_value + last;
- c->multiplicands[j] = val;
- if (c->sequence_p)
- last = val;
- }
- }
- #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK
- skip:;
- #endif
- setup_temp_free(f, mults, sizeof(mults[0])*c->lookup_values);
- CHECK(f);
- }
- CHECK(f);
- }
- x = get_bits(f, 6) + 1;
- for (i=0; i < x; ++i) {
- uint32 z = get_bits(f, 16);
- if (z != 0) return error(f, VORBIS_invalid_setup);
- }
- f->floor_count = get_bits(f, 6)+1;
- f->floor_config = (Floor *) setup_malloc(f, f->floor_count * sizeof(*f->floor_config));
- if (f->floor_config == NULL) return error(f, VORBIS_outofmem);
- for (i=0; i < f->floor_count; ++i) {
- f->floor_types[i] = get_bits(f, 16);
- if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup);
- if (f->floor_types[i] == 0) {
- Floor0 *g = &f->floor_config[i].floor0;
- g->order = get_bits(f,8);
- g->rate = get_bits(f,16);
- g->bark_map_size = get_bits(f,16);
- g->amplitude_bits = get_bits(f,6);
- g->amplitude_offset = get_bits(f,8);
- g->number_of_books = get_bits(f,4) + 1;
- for (j=0; j < g->number_of_books; ++j)
- g->book_list[j] = get_bits(f,8);
- return error(f, VORBIS_feature_not_supported);
- } else {
- stbv__floor_ordering p[31*8+2];
- Floor1 *g = &f->floor_config[i].floor1;
- int max_class = -1;
- g->partitions = get_bits(f, 5);
- for (j=0; j < g->partitions; ++j) {
- g->partition_class_list[j] = get_bits(f, 4);
- if (g->partition_class_list[j] > max_class)
- max_class = g->partition_class_list[j];
- }
- for (j=0; j <= max_class; ++j) {
- g->class_dimensions[j] = get_bits(f, 3)+1;
- g->class_subclasses[j] = get_bits(f, 2);
- if (g->class_subclasses[j]) {
- g->class_masterbooks[j] = get_bits(f, 8);
- if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
- }
- for (k=0; k < 1 << g->class_subclasses[j]; ++k) {
- g->subclass_books[j][k] = (int16)get_bits(f,8)-1;
- if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
- }
- }
- g->floor1_multiplier = get_bits(f,2)+1;
- g->rangebits = get_bits(f,4);
- g->Xlist[0] = 0;
- g->Xlist[1] = 1 << g->rangebits;
- g->values = 2;
- for (j=0; j < g->partitions; ++j) {
- int c = g->partition_class_list[j];
- for (k=0; k < g->class_dimensions[c]; ++k) {
- g->Xlist[g->values] = get_bits(f, g->rangebits);
- ++g->values;
- }
- }
- for (j=0; j < g->values; ++j) {
- p[j].x = g->Xlist[j];
- p[j].id = j;
- }
- qsort(p, g->values, sizeof(p[0]), point_compare);
- for (j=0; j < g->values-1; ++j)
- if (p[j].x == p[j+1].x)
- return error(f, VORBIS_invalid_setup);
- for (j=0; j < g->values; ++j)
- g->sorted_order[j] = (uint8) p[j].id;
- for (j=2; j < g->values; ++j) {
- int low = 0,hi = 0;
- neighbors(g->Xlist, j, &low,&hi);
- g->neighbors[j][0] = low;
- g->neighbors[j][1] = hi;
- }
- if (g->values > longest_floorlist)
- longest_floorlist = g->values;
- }
- }
- f->residue_count = get_bits(f, 6)+1;
- f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(f->residue_config[0]));
- if (f->residue_config == NULL) return error(f, VORBIS_outofmem);
- memset(f->residue_config, 0, f->residue_count * sizeof(f->residue_config[0]));
- for (i=0; i < f->residue_count; ++i) {
- uint8 residue_cascade[64];
- Residue *r = f->residue_config+i;
- f->residue_types[i] = get_bits(f, 16);
- if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup);
- r->begin = get_bits(f, 24);
- r->end = get_bits(f, 24);
- if (r->end < r->begin) return error(f, VORBIS_invalid_setup);
- r->part_size = get_bits(f,24)+1;
- r->classifications = get_bits(f,6)+1;
- r->classbook = get_bits(f,8);
- if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup);
- for (j=0; j < r->classifications; ++j) {
- uint8 high_bits=0;
- uint8 low_bits=get_bits(f,3);
- if (get_bits(f,1))
- high_bits = get_bits(f,5);
- residue_cascade[j] = high_bits*8 + low_bits;
- }
- r->residue_books = (short (*)[8]) setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications);
- if (r->residue_books == NULL) return error(f, VORBIS_outofmem);
- for (j=0; j < r->classifications; ++j) {
- for (k=0; k < 8; ++k) {
- if (residue_cascade[j] & (1 << k)) {
- r->residue_books[j][k] = get_bits(f, 8);
- if (r->residue_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup);
- } else {
- r->residue_books[j][k] = -1;
- }
- }
- }
- r->classdata = (uint8 **) setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries);
- if (!r->classdata) return error(f, VORBIS_outofmem);
- memset(r->classdata, 0, sizeof(*r->classdata) * f->codebooks[r->classbook].entries);
- for (j=0; j < f->codebooks[r->classbook].entries; ++j) {
- int classwords = f->codebooks[r->classbook].dimensions;
- int temp = j;
- r->classdata[j] = (uint8 *) setup_malloc(f, sizeof(r->classdata[j][0]) * classwords);
- if (r->classdata[j] == NULL) return error(f, VORBIS_outofmem);
- for (k=classwords-1; k >= 0; --k) {
- r->classdata[j][k] = temp % r->classifications;
- temp /= r->classifications;
- }
- }
- }
- f->mapping_count = get_bits(f,6)+1;
- f->mapping = (Mapping *) setup_malloc(f, f->mapping_count * sizeof(*f->mapping));
- if (f->mapping == NULL) return error(f, VORBIS_outofmem);
- memset(f->mapping, 0, f->mapping_count * sizeof(*f->mapping));
- for (i=0; i < f->mapping_count; ++i) {
- Mapping *m = f->mapping + i;
- int mapping_type = get_bits(f,16);
- if (mapping_type != 0) return error(f, VORBIS_invalid_setup);
- m->chan = (MappingChannel *) setup_malloc(f, f->channels * sizeof(*m->chan));
- if (m->chan == NULL) return error(f, VORBIS_outofmem);
- if (get_bits(f,1))
- m->submaps = get_bits(f,4)+1;
- else
- m->submaps = 1;
- if (m->submaps > max_submaps)
- max_submaps = m->submaps;
- if (get_bits(f,1)) {
- m->coupling_steps = get_bits(f,8)+1;
- if (m->coupling_steps > f->channels) return error(f, VORBIS_invalid_setup);
- for (k=0; k < m->coupling_steps; ++k) {
- m->chan[k].magnitude = get_bits(f, ilog(f->channels-1));
- m->chan[k].angle = get_bits(f, ilog(f->channels-1));
- if (m->chan[k].magnitude >= f->channels) return error(f, VORBIS_invalid_setup);
- if (m->chan[k].angle >= f->channels) return error(f, VORBIS_invalid_setup);
- if (m->chan[k].magnitude == m->chan[k].angle) return error(f, VORBIS_invalid_setup);
- }
- } else
- m->coupling_steps = 0;
- if (get_bits(f,2)) return error(f, VORBIS_invalid_setup);
- if (m->submaps > 1) {
- for (j=0; j < f->channels; ++j) {
- m->chan[j].mux = get_bits(f, 4);
- if (m->chan[j].mux >= m->submaps) return error(f, VORBIS_invalid_setup);
- }
- } else
- for (j=0; j < f->channels; ++j)
- m->chan[j].mux = 0;
- for (j=0; j < m->submaps; ++j) {
- get_bits(f,8);
- m->submap_floor[j] = get_bits(f,8);
- m->submap_residue[j] = get_bits(f,8);
- if (m->submap_floor[j] >= f->floor_count) return error(f, VORBIS_invalid_setup);
- if (m->submap_residue[j] >= f->residue_count) return error(f, VORBIS_invalid_setup);
- }
- }
- f->mode_count = get_bits(f, 6)+1;
- for (i=0; i < f->mode_count; ++i) {
- Mode *m = f->mode_config+i;
- m->blockflag = get_bits(f,1);
- m->windowtype = get_bits(f,16);
- m->transformtype = get_bits(f,16);
- m->mapping = get_bits(f,8);
- if (m->windowtype != 0) return error(f, VORBIS_invalid_setup);
- if (m->transformtype != 0) return error(f, VORBIS_invalid_setup);
- if (m->mapping >= f->mapping_count) return error(f, VORBIS_invalid_setup);
- }
- flush_packet(f);
- f->previous_length = 0;
- for (i=0; i < f->channels; ++i) {
- f->channel_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1);
- f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
- f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist);
- if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem);
- memset(f->channel_buffers[i], 0, sizeof(float) * f->blocksize_1);
- #ifdef STB_VORBIS_NO_DEFER_FLOOR
- f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2);
- if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem);
- #endif
- }
- if (!init_blocksize(f, 0, f->blocksize_0)) return FALSE;
- if (!init_blocksize(f, 1, f->blocksize_1)) return FALSE;
- f->blocksize[0] = f->blocksize_0;
- f->blocksize[1] = f->blocksize_1;
- #ifdef STB_VORBIS_DIVIDE_TABLE
- if (integer_divide_table[1][1]==0)
- for (i=0; i < DIVTAB_NUMER; ++i)
- for (j=1; j < DIVTAB_DENOM; ++j)
- integer_divide_table[i][j] = i / j;
- #endif
- {
- uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1);
- uint32 classify_mem;
- int i,max_part_read=0;
- for (i=0; i < f->residue_count; ++i) {
- Residue *r = f->residue_config + i;
- unsigned int actual_size = f->blocksize_1 / 2;
- unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size;
- unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size;
- int n_read = limit_r_end - limit_r_begin;
- int part_read = n_read / r->part_size;
- if (part_read > max_part_read)
- max_part_read = part_read;
- }
- #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE
- classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(uint8 *));
- #else
- classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *));
- #endif
- f->temp_memory_required = classify_mem;
- if (imdct_mem > f->temp_memory_required)
- f->temp_memory_required = imdct_mem;
- }
- if (f->alloc.alloc_buffer) {
- assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes);
- if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned) f->temp_offset)
- return error(f, VORBIS_outofmem);
- }
- if (f->next_seg == -1) {
- f->first_audio_page_offset = stb_vorbis_get_file_offset(f);
- } else {
- f->first_audio_page_offset = 0;
- }
- return TRUE;
- }
- static void vorbis_deinit(stb_vorbis *p)
- {
- int i,j;
- setup_free(p, p->vendor);
- for (i=0; i < p->comment_list_length; ++i) {
- setup_free(p, p->comment_list[i]);
- }
- setup_free(p, p->comment_list);
- if (p->residue_config) {
- for (i=0; i < p->residue_count; ++i) {
- Residue *r = p->residue_config+i;
- if (r->classdata) {
- for (j=0; j < p->codebooks[r->classbook].entries; ++j)
- setup_free(p, r->classdata[j]);
- setup_free(p, r->classdata);
- }
- setup_free(p, r->residue_books);
- }
- }
- if (p->codebooks) {
- CHECK(p);
- for (i=0; i < p->codebook_count; ++i) {
- Codebook *c = p->codebooks + i;
- setup_free(p, c->codeword_lengths);
- setup_free(p, c->multiplicands);
- setup_free(p, c->codewords);
- setup_free(p, c->sorted_codewords);
- setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL);
- }
- setup_free(p, p->codebooks);
- }
- setup_free(p, p->floor_config);
- setup_free(p, p->residue_config);
- if (p->mapping) {
- for (i=0; i < p->mapping_count; ++i)
- setup_free(p, p->mapping[i].chan);
- setup_free(p, p->mapping);
- }
- CHECK(p);
- for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) {
- setup_free(p, p->channel_buffers[i]);
- setup_free(p, p->previous_window[i]);
- #ifdef STB_VORBIS_NO_DEFER_FLOOR
- setup_free(p, p->floor_buffers[i]);
- #endif
- setup_free(p, p->finalY[i]);
- }
- for (i=0; i < 2; ++i) {
- setup_free(p, p->A[i]);
- setup_free(p, p->B[i]);
- setup_free(p, p->C[i]);
- setup_free(p, p->window[i]);
- setup_free(p, p->bit_reverse[i]);
- }
- }
- void stb_vorbis_close(stb_vorbis *p)
- {
- if (p == NULL) return;
- vorbis_deinit(p);
- setup_free(p,p);
- }
- static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z)
- {
- memset(p, 0, sizeof(*p));
- if (z) {
- p->alloc = *z;
- p->alloc.alloc_buffer_length_in_bytes &= ~7;
- p->temp_offset = p->alloc.alloc_buffer_length_in_bytes;
- }
- p->eof = 0;
- p->error = VORBIS__no_error;
- p->stream = NULL;
- p->codebooks = NULL;
- p->page_crc_tests = -1;
- }
- int stb_vorbis_get_sample_offset(stb_vorbis *f)
- {
- if (f->current_loc_valid)
- return f->current_loc;
- else
- return -1;
- }
- stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f)
- {
- stb_vorbis_info d;
- d.channels = f->channels;
- d.sample_rate = f->sample_rate;
- d.setup_memory_required = f->setup_memory_required;
- d.setup_temp_memory_required = f->setup_temp_memory_required;
- d.temp_memory_required = f->temp_memory_required;
- d.max_frame_size = f->blocksize_1 >> 1;
- return d;
- }
- stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f)
- {
- stb_vorbis_comment d;
- d.vendor = f->vendor;
- d.comment_list_length = f->comment_list_length;
- d.comment_list = f->comment_list;
- return d;
- }
- int stb_vorbis_get_error(stb_vorbis *f)
- {
- int e = f->error;
- f->error = VORBIS__no_error;
- return e;
- }
- static stb_vorbis * vorbis_alloc(stb_vorbis *f)
- {
- stb_vorbis *p = (stb_vorbis *) setup_malloc(f, sizeof(*p));
- return p;
- }
- unsigned int stb_vorbis_get_file_offset(stb_vorbis *f)
- {
- if (USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start);
- }
- #ifndef STB_VORBIS_NO_PULLDATA_API
- static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last)
- {
- for(;;) {
- int n;
- if (f->eof) return 0;
- n = get8(f);
- if (n == 0x4f) {
- unsigned int retry_loc = stb_vorbis_get_file_offset(f);
- int i;
- if (retry_loc - 25 > f->stream_len)
- return 0;
- for (i=1; i < 4; ++i)
- if (get8(f) != ogg_page_header[i])
- break;
- if (f->eof) return 0;
- if (i == 4) {
- uint8 header[27];
- uint32 i, crc, goal, len;
- for (i=0; i < 4; ++i)
- header[i] = ogg_page_header[i];
- for (; i < 27; ++i)
- header[i] = get8(f);
- if (f->eof) return 0;
- if (header[4] != 0) goto invalid;
- goal = header[22] + (header[23] << 8) + (header[24]<<16) + ((uint32)header[25]<<24);
- for (i=22; i < 26; ++i)
- header[i] = 0;
- crc = 0;
- for (i=0; i < 27; ++i)
- crc = crc32_update(crc, header[i]);
- len = 0;
- for (i=0; i < header[26]; ++i) {
- int s = get8(f);
- crc = crc32_update(crc, s);
- len += s;
- }
- if (len && f->eof) return 0;
- for (i=0; i < len; ++i)
- crc = crc32_update(crc, get8(f));
- if (crc == goal) {
- if (end)
- *end = stb_vorbis_get_file_offset(f);
- if (last) {
- if (header[5] & 0x04)
- *last = 1;
- else
- *last = 0;
- }
- set_file_offset(f, retry_loc-1);
- return 1;
- }
- }
- invalid:
- set_file_offset(f, retry_loc);
- }
- }
- }
- #define SAMPLE_unknown 0xffffffff
- static int get_seek_page_info(stb_vorbis *f, ProbedPage *z)
- {
- uint8 header[27] = { 0 }, lacing[255];
- int i,len;
- z->page_start = stb_vorbis_get_file_offset(f);
- getn(f, header, 27);
- if (header[0] != 'O' || header[1] != 'g' || header[2] != 'g' || header[3] != 'S')
- return 0;
- getn(f, lacing, header[26]);
- len = 0;
- for (i=0; i < header[26]; ++i)
- len += lacing[i];
- z->page_end = z->page_start + 27 + header[26] + len;
- z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 24);
- set_file_offset(f, z->page_start);
- return 1;
- }
- static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset)
- {
- unsigned int previous_safe, end;
- if (limit_offset >= 65536 && limit_offset-65536 >= f->first_audio_page_offset)
- previous_safe = limit_offset - 65536;
- else
- previous_safe = f->first_audio_page_offset;
- set_file_offset(f, previous_safe);
- while (vorbis_find_page(f, &end, NULL)) {
- if (end >= limit_offset && stb_vorbis_get_file_offset(f) < limit_offset)
- return 1;
- set_file_offset(f, end);
- }
- return 0;
- }
- static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number)
- {
- ProbedPage left, right, mid;
- int i, start_seg_with_known_loc, end_pos, page_start;
- uint32 delta, stream_length, padding, last_sample_limit;
- double offset = 0.0, bytes_per_sample = 0.0;
- int probe = 0;
- stream_length = stb_vorbis_stream_length_in_samples(f);
- if (stream_length == 0) return error(f, VORBIS_seek_without_length);
- if (sample_number > stream_length) return error(f, VORBIS_seek_invalid);
- padding = ((f->blocksize_1 - f->blocksize_0) >> 2);
- if (sample_number < padding)
- last_sample_limit = 0;
- else
- last_sample_limit = sample_number - padding;
- left = f->p_first;
- while (left.last_decoded_sample == ~0U) {
- set_file_offset(f, left.page_end);
- if (!get_seek_page_info(f, &left)) goto error;
- }
- right = f->p_last;
- assert(right.last_decoded_sample != ~0U);
- if (last_sample_limit <= left.last_decoded_sample) {
- if (stb_vorbis_seek_start(f)) {
- if (f->current_loc > sample_number)
- return error(f, VORBIS_seek_failed);
- return 1;
- }
- return 0;
- }
- while (left.page_end != right.page_start) {
- assert(left.page_end < right.page_start);
- delta = right.page_start - left.page_end;
- if (delta <= 65536) {
- set_file_offset(f, left.page_end);
- } else {
- if (probe < 2) {
- if (probe == 0) {
- double data_bytes = right.page_end - left.page_start;
- bytes_per_sample = data_bytes / right.last_decoded_sample;
- offset = left.page_start + bytes_per_sample * (last_sample_limit - left.last_decoded_sample);
- } else {
- double error = ((double) last_sample_limit - mid.last_decoded_sample) * bytes_per_sample;
- if (error >= 0 && error < 8000) error = 8000;
- if (error < 0 && error > -8000) error = -8000;
- offset += error * 2;
- }
- if (offset < left.page_end)
- offset = left.page_end;
- if (offset > right.page_start - 65536)
- offset = right.page_start - 65536;
- set_file_offset(f, (unsigned int) offset);
- } else {
- set_file_offset(f, left.page_end + (delta / 2) - 32768);
- }
- if (!vorbis_find_page(f, NULL, NULL)) goto error;
- }
- for (;;) {
- if (!get_seek_page_info(f, &mid)) goto error;
- if (mid.last_decoded_sample != ~0U) break;
- set_file_offset(f, mid.page_end);
- assert(mid.page_start < right.page_start);
- }
- if (mid.page_start == right.page_start) {
- if (probe >= 2 || delta <= 65536)
- break;
- } else {
- if (last_sample_limit < mid.last_decoded_sample)
- right = mid;
- else
- left = mid;
- }
- ++probe;
- }
- page_start = left.page_start;
- set_file_offset(f, page_start);
- if (!start_page(f)) return error(f, VORBIS_seek_failed);
- end_pos = f->end_seg_with_known_loc;
- assert(end_pos >= 0);
- for (;;) {
- for (i = end_pos; i > 0; --i)
- if (f->segments[i-1] != 255)
- break;
- start_seg_with_known_loc = i;
- if (start_seg_with_known_loc > 0 || !(f->page_flag & PAGEFLAG_continued_packet))
- break;
- if (!go_to_page_before(f, page_start))
- goto error;
- page_start = stb_vorbis_get_file_offset(f);
- if (!start_page(f)) goto error;
- end_pos = f->segment_count - 1;
- }
- f->current_loc_valid = FALSE;
- f->last_seg = FALSE;
- f->valid_bits = 0;
- f->packet_bytes = 0;
- f->bytes_in_seg = 0;
- f->previous_length = 0;
- f->next_seg = start_seg_with_known_loc;
- for (i = 0; i < start_seg_with_known_loc; i++)
- skip(f, f->segments[i]);
- if (!vorbis_pump_first_frame(f))
- return 0;
- if (f->current_loc > sample_number)
- return error(f, VORBIS_seek_failed);
- return 1;
- error:
- stb_vorbis_seek_start(f);
- return error(f, VORBIS_seek_failed);
- }
- static int peek_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode)
- {
- int bits_read, bytes_read;
- if (!vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode))
- return 0;
- bits_read = 1 + ilog(f->mode_count-1);
- if (f->mode_config[*mode].blockflag)
- bits_read += 2;
- bytes_read = (bits_read + 7) / 8;
- f->bytes_in_seg += bytes_read;
- f->packet_bytes -= bytes_read;
- skip(f, -bytes_read);
- if (f->next_seg == -1)
- f->next_seg = f->segment_count - 1;
- else
- f->next_seg--;
- f->valid_bits = 0;
- return 1;
- }
- int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number)
- {
- uint32 max_frame_samples;
- if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
- if (!seek_to_sample_coarse(f, sample_number))
- return 0;
- assert(f->current_loc_valid);
- assert(f->current_loc <= sample_number);
- max_frame_samples = (f->blocksize_1*3 - f->blocksize_0) >> 2;
- while (f->current_loc < sample_number) {
- int left_start, left_end, right_start, right_end, mode, frame_samples;
- if (!peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode))
- return error(f, VORBIS_seek_failed);
- frame_samples = right_start - left_start;
- if (f->current_loc + frame_samples > sample_number) {
- return 1;
- } else if (f->current_loc + frame_samples + max_frame_samples > sample_number) {
- vorbis_pump_first_frame(f);
- } else {
- f->current_loc += frame_samples;
- f->previous_length = 0;
- maybe_start_packet(f);
- flush_packet(f);
- }
- }
- if (f->current_loc != sample_number) return error(f, VORBIS_seek_failed);
- return 1;
- }
- int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number)
- {
- if (!stb_vorbis_seek_frame(f, sample_number))
- return 0;
- if (sample_number != f->current_loc) {
- int n;
- uint32 frame_start = f->current_loc;
- stb_vorbis_get_frame_float(f, &n, NULL);
- assert(sample_number > frame_start);
- assert(f->channel_buffer_start + (int) (sample_number-frame_start) <= f->channel_buffer_end);
- f->channel_buffer_start += (sample_number - frame_start);
- }
- return 1;
- }
- int stb_vorbis_seek_start(stb_vorbis *f)
- {
- if (IS_PUSH_MODE(f)) { return error(f, VORBIS_invalid_api_mixing); }
- set_file_offset(f, f->first_audio_page_offset);
- f->previous_length = 0;
- f->first_decode = TRUE;
- f->next_seg = -1;
- return vorbis_pump_first_frame(f);
- }
- unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f)
- {
- unsigned int restore_offset, previous_safe;
- unsigned int end, last_page_loc;
- if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
- if (!f->total_samples) {
- unsigned int last;
- uint32 lo,hi;
- char header[6];
- restore_offset = stb_vorbis_get_file_offset(f);
- if (f->stream_len >= 65536 && f->stream_len-65536 >= f->first_audio_page_offset)
- previous_safe = f->stream_len - 65536;
- else
- previous_safe = f->first_audio_page_offset;
- set_file_offset(f, previous_safe);
- if (!vorbis_find_page(f, &end, &last)) {
- f->error = VORBIS_cant_find_last_page;
- f->total_samples = 0xffffffff;
- goto done;
- }
- last_page_loc = stb_vorbis_get_file_offset(f);
- while (!last) {
- set_file_offset(f, end);
- if (!vorbis_find_page(f, &end, &last)) {
- break;
- }
- last_page_loc = stb_vorbis_get_file_offset(f);
- }
- set_file_offset(f, last_page_loc);
- getn(f, (unsigned char *)header, 6);
- lo = get32(f);
- hi = get32(f);
- if (lo == 0xffffffff && hi == 0xffffffff) {
- f->error = VORBIS_cant_find_last_page;
- f->total_samples = SAMPLE_unknown;
- goto done;
- }
- if (hi)
- lo = 0xfffffffe;
- f->total_samples = lo;
- f->p_last.page_start = last_page_loc;
- f->p_last.page_end = end;
- f->p_last.last_decoded_sample = lo;
- done:
- set_file_offset(f, restore_offset);
- }
- return f->total_samples == SAMPLE_unknown ? 0 : f->total_samples;
- }
- float stb_vorbis_stream_length_in_seconds(stb_vorbis *f)
- {
- return stb_vorbis_stream_length_in_samples(f) / (float) f->sample_rate;
- }
- int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output)
- {
- int len, right,left,i;
- if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing);
- if (!vorbis_decode_packet(f, &len, &left, &right)) {
- f->channel_buffer_start = f->channel_buffer_end = 0;
- return 0;
- }
- len = vorbis_finish_frame(f, len, left, right);
- for (i=0; i < f->channels; ++i)
- f->outputs[i] = f->channel_buffers[i] + left;
- f->channel_buffer_start = left;
- f->channel_buffer_end = left+len;
- if (channels) *channels = f->channels;
- if (output) *output = f->outputs;
- return len;
- }
- stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc)
- {
- stb_vorbis *f, p;
- if (!data) {
- if (error) *error = VORBIS_unexpected_eof;
- return NULL;
- }
- vorbis_init(&p, alloc);
- p.stream = (uint8 *) data;
- p.stream_end = (uint8 *) data + len;
- p.stream_start = (uint8 *) p.stream;
- p.stream_len = len;
- p.push_mode = FALSE;
- if (start_decoder(&p)) {
- f = vorbis_alloc(&p);
- if (f) {
- *f = p;
- vorbis_pump_first_frame(f);
- if (error) *error = VORBIS__no_error;
- return f;
- }
- }
- if (error) *error = p.error;
- vorbis_deinit(&p);
- return NULL;
- }
- #ifndef STB_VORBIS_NO_INTEGER_CONVERSION
- #define PLAYBACK_MONO 1
- #define PLAYBACK_LEFT 2
- #define PLAYBACK_RIGHT 4
- #define L (PLAYBACK_LEFT | PLAYBACK_MONO)
- #define C (PLAYBACK_LEFT | PLAYBACK_RIGHT | PLAYBACK_MONO)
- #define R (PLAYBACK_RIGHT | PLAYBACK_MONO)
- static int8 channel_position[7][6] =
- {
- { 0 },
- { C },
- { L, R },
- { L, C, R },
- { L, R, L, R },
- { L, C, R, L, R },
- { L, C, R, L, R, C },
- };
- #ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT
- typedef union {
- float f;
- int i;
- } float_conv;
- typedef char stb_vorbis_float_size_test[sizeof(float)==4 && sizeof(int) == 4];
- #define FASTDEF(x) float_conv x
- #define MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT))
- #define ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22))
- #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + MAGIC(s), temp.i - ADDEND(s))
- #define check_endianness()
- #else
- #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s))))
- #define check_endianness()
- #define FASTDEF(x)
- #endif
- static void copy_samples(short *dest, float *src, int len)
- {
- int i;
- check_endianness();
- for (i=0; i < len; ++i) {
- FASTDEF(temp);
- int v = FAST_SCALED_FLOAT_TO_INT(temp, src[i],15);
- if ((unsigned int) (v + 32768) > 65535)
- v = v < 0 ? -32768 : 32767;
- dest[i] = v;
- }
- }
- static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len)
- {
- #define STB_BUFFER_SIZE 32
- float buffer[STB_BUFFER_SIZE];
- int i,j,o,n = STB_BUFFER_SIZE;
- check_endianness();
- for (o = 0; o < len; o += STB_BUFFER_SIZE) {
- memset(buffer, 0, sizeof(buffer));
- if (o + n > len) n = len - o;
- for (j=0; j < num_c; ++j) {
- if (channel_position[num_c][j] & mask) {
- for (i=0; i < n; ++i)
- buffer[i] += data[j][d_offset+o+i];
- }
- }
- for (i=0; i < n; ++i) {
- FASTDEF(temp);
- int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15);
- if ((unsigned int) (v + 32768) > 65535)
- v = v < 0 ? -32768 : 32767;
- output[o+i] = v;
- }
- }
- #undef STB_BUFFER_SIZE
- }
- static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len)
- {
- #define STB_BUFFER_SIZE 32
- float buffer[STB_BUFFER_SIZE];
- int i,j,o,n = STB_BUFFER_SIZE >> 1;
- check_endianness();
- for (o = 0; o < len; o += STB_BUFFER_SIZE >> 1) {
- int o2 = o << 1;
- memset(buffer, 0, sizeof(buffer));
- if (o + n > len) n = len - o;
- for (j=0; j < num_c; ++j) {
- int m = channel_position[num_c][j] & (PLAYBACK_LEFT | PLAYBACK_RIGHT);
- if (m == (PLAYBACK_LEFT | PLAYBACK_RIGHT)) {
- for (i=0; i < n; ++i) {
- buffer[i*2+0] += data[j][d_offset+o+i];
- buffer[i*2+1] += data[j][d_offset+o+i];
- }
- } else if (m == PLAYBACK_LEFT) {
- for (i=0; i < n; ++i) {
- buffer[i*2+0] += data[j][d_offset+o+i];
- }
- } else if (m == PLAYBACK_RIGHT) {
- for (i=0; i < n; ++i) {
- buffer[i*2+1] += data[j][d_offset+o+i];
- }
- }
- }
- for (i=0; i < (n<<1); ++i) {
- FASTDEF(temp);
- int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15);
- if ((unsigned int) (v + 32768) > 65535)
- v = v < 0 ? -32768 : 32767;
- output[o2+i] = v;
- }
- }
- #undef STB_BUFFER_SIZE
- }
- static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples)
- {
- int i;
- if (buf_c != data_c && buf_c <= 2 && data_c <= 6) {
- static int channel_selector[3][2] = { {0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT} };
- for (i=0; i < buf_c; ++i)
- compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples);
- } else {
- int limit = buf_c < data_c ? buf_c : data_c;
- for (i=0; i < limit; ++i)
- copy_samples(buffer[i]+b_offset, data[i]+d_offset, samples);
- for ( ; i < buf_c; ++i)
- memset(buffer[i]+b_offset, 0, sizeof(short) * samples);
- }
- }
- int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples)
- {
- float **output = NULL;
- int len = stb_vorbis_get_frame_float(f, NULL, &output);
- if (len > num_samples) len = num_samples;
- if (len)
- convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len);
- return len;
- }
- static void convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len)
- {
- int i;
- check_endianness();
- if (buf_c != data_c && buf_c <= 2 && data_c <= 6) {
- assert(buf_c == 2);
- for (i=0; i < buf_c; ++i)
- compute_stereo_samples(buffer, data_c, data, d_offset, len);
- } else {
- int limit = buf_c < data_c ? buf_c : data_c;
- int j;
- for (j=0; j < len; ++j) {
- for (i=0; i < limit; ++i) {
- FASTDEF(temp);
- float f = data[i][d_offset+j];
- int v = FAST_SCALED_FLOAT_TO_INT(temp, f,15);
- if ((unsigned int) (v + 32768) > 65535)
- v = v < 0 ? -32768 : 32767;
- *buffer++ = v;
- }
- for ( ; i < buf_c; ++i)
- *buffer++ = 0;
- }
- }
- }
- int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts)
- {
- float **output;
- int len;
- if (num_c == 1) return stb_vorbis_get_frame_short(f,num_c,&buffer, num_shorts);
- len = stb_vorbis_get_frame_float(f, NULL, &output);
- if (len) {
- if (len*num_c > num_shorts) len = num_shorts / num_c;
- convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len);
- }
- return len;
- }
- int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts)
- {
- float **outputs;
- int len = num_shorts / channels;
- int n=0;
- while (n < len) {
- int k = f->channel_buffer_end - f->channel_buffer_start;
- if (n+k >= len) k = len - n;
- if (k)
- convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k);
- buffer += k*channels;
- n += k;
- f->channel_buffer_start += k;
- if (n == len) break;
- if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break;
- }
- return n;
- }
- int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len)
- {
- float **outputs;
- int n=0;
- while (n < len) {
- int k = f->channel_buffer_end - f->channel_buffer_start;
- if (n+k >= len) k = len - n;
- if (k)
- convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k);
- n += k;
- f->channel_buffer_start += k;
- if (n == len) break;
- if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break;
- }
- return n;
- }
- int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *sample_rate, short **output)
- {
- int data_len, offset, total, limit, error;
- short *data;
- stb_vorbis *v = stb_vorbis_open_memory(mem, len, &error, NULL);
- if (v == NULL) return -1;
- limit = v->channels * 4096;
- *channels = v->channels;
- if (sample_rate)
- *sample_rate = v->sample_rate;
- offset = data_len = 0;
- total = limit;
- data = (short *) malloc(total * sizeof(*data));
- if (data == NULL) {
- stb_vorbis_close(v);
- return -2;
- }
- for (;;) {
- int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset);
- if (n == 0) break;
- data_len += n;
- offset += n * v->channels;
- if (offset + limit > total) {
- short *data2;
- total *= 2;
- data2 = (short *) realloc(data, total * sizeof(*data));
- if (data2 == NULL) {
- free(data);
- stb_vorbis_close(v);
- return -2;
- }
- data = data2;
- }
- }
- *output = data;
- stb_vorbis_close(v);
- return data_len;
- }
- #endif
- int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats)
- {
- float **outputs;
- int len = num_floats / channels;
- int n=0;
- int z = f->channels;
- if (z > channels) z = channels;
- while (n < len) {
- int i,j;
- int k = f->channel_buffer_end - f->channel_buffer_start;
- if (n+k >= len) k = len - n;
- for (j=0; j < k; ++j) {
- for (i=0; i < z; ++i)
- *buffer++ = f->channel_buffers[i][f->channel_buffer_start+j];
- for ( ; i < channels; ++i)
- *buffer++ = 0;
- }
- n += k;
- f->channel_buffer_start += k;
- if (n == len)
- break;
- if (!stb_vorbis_get_frame_float(f, NULL, &outputs))
- break;
- }
- return n;
- }
- int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples)
- {
- float **outputs;
- int n=0;
- int z = f->channels;
- if (z > channels) z = channels;
- while (n < num_samples) {
- int i;
- int k = f->channel_buffer_end - f->channel_buffer_start;
- if (n+k >= num_samples) k = num_samples - n;
- if (k) {
- for (i=0; i < z; ++i)
- memcpy(buffer[i]+n, f->channel_buffers[i]+f->channel_buffer_start, sizeof(float)*k);
- for ( ; i < channels; ++i)
- memset(buffer[i]+n, 0, sizeof(float) * k);
- }
- n += k;
- f->channel_buffer_start += k;
- if (n == num_samples)
- break;
- if (!stb_vorbis_get_frame_float(f, NULL, &outputs))
- break;
- }
- return n;
- }
- #endif
- #endif
- #endif
- #if !defined(SSFN_HEADERONLY) && !defined(SSFN_IMPLEMENTATION)
- #define SSFN_IMPLEMENTATION
- #define SSFN_MAXLINES 1024
- #endif
- /* ssfn.h - Scalable Screen Font - MIT license
- https://gitlab.com/bztsrc/scalable-font2 */
- /**************** embeded ssfn.h ****************/
- #ifndef _SSFN_H_
- #define _SSFN_H_
- #define SSFN_VERSION 0x0200
- #ifndef _STDINT_H
- typedef unsigned char uint8_t;
- typedef unsigned short int uint16_t;
- typedef short int int16_t;
- typedef unsigned int uint32_t;
- #ifndef _UINT64_T
- typedef unsigned long int uint64_t;
- #endif
- #endif
- #define SSFN_MAGIC "SFN2"
- #define SSFN_COLLECTION "SFNC"
- #define SSFN_ENDMAGIC "2NFS"
- #define SSFN_LIG_FIRST 0xF000
- #define SSFN_LIG_LAST 0xF8FF
- #define SSFN_TYPE_FAMILY(x) ((x)&15)
- #define SSFN_FAMILY_SERIF 0
- #define SSFN_FAMILY_SANS 1
- #define SSFN_FAMILY_DECOR 2
- #define SSFN_FAMILY_MONOSPACE 3
- #define SSFN_FAMILY_HAND 4
- #define SSFN_TYPE_STYLE(x) (((x)>>4)&15)
- #define SSFN_STYLE_REGULAR 0
- #define SSFN_STYLE_BOLD 1
- #define SSFN_STYLE_ITALIC 2
- #define SSFN_STYLE_USRDEF1 4
- #define SSFN_STYLE_USRDEF2 8
- #define SSFN_CONTOUR_MOVE 0
- #define SSFN_CONTOUR_LINE 1
- #define SSFN_CONTOUR_QUAD 2
- #define SSFN_CONTOUR_CUBIC 3
- #define SSFN_FRAG_CONTOUR 0
- #define SSFN_FRAG_BITMAP 1
- #define SSFN_FRAG_PIXMAP 2
- #define SSFN_FRAG_KERNING 3
- #define SSFN_FRAG_HINTING 4
- #ifndef _MSC_VER
- #define _pack __attribute__((packed))
- #else
- #define _pack
- #pragma pack(push)
- #pragma pack(1)
- #endif
- typedef struct {
- uint8_t magic[4];
- uint32_t size;
- uint8_t type;
- uint8_t features;
- uint8_t width;
- uint8_t height;
- uint8_t baseline;
- uint8_t underline;
- uint16_t fragments_offs;
- uint32_t characters_offs;
- uint32_t ligature_offs;
- uint32_t kerning_offs;
- uint32_t cmap_offs;
- } _pack ssfn_font_t;
- #ifdef _MSC_VER
- #pragma pack(pop)
- #endif
- #define SSFN_FAMILY_ANY 0xff
- #define SSFN_FAMILY_BYNAME 0xfe
- #define SSFN_STYLE_UNDERLINE 16
- #define SSFN_STYLE_STHROUGH 32
- #define SSFN_STYLE_NOAA 64
- #define SSFN_STYLE_NOKERN 128
- #define SSFN_STYLE_NODEFGLYPH 256
- #define SSFN_STYLE_NOCACHE 512
- #define SSFN_STYLE_NOHINTING 1024
- #define SSFN_STYLE_RTL 2048
- #define SSFN_STYLE_ABS_SIZE 4096
- #define SSFN_STYLE_NOSMOOTH 8192
- #define SSFN_OK 0
- #define SSFN_ERR_ALLOC -1
- #define SSFN_ERR_BADFILE -2
- #define SSFN_ERR_NOFACE -3
- #define SSFN_ERR_INVINP -4
- #define SSFN_ERR_BADSTYLE -5
- #define SSFN_ERR_BADSIZE -6
- #define SSFN_ERR_NOGLYPH -7
- #define SSFN_SIZE_MAX 192
- #define SSFN_ITALIC_DIV 4
- #define SSFN_PREC 4
- typedef struct {
- uint8_t *ptr;
- int w;
- int h;
- uint16_t p;
- int x;
- int y;
- uint32_t fg;
- uint32_t bg;
- } ssfn_buf_t;
- #define SSFN_DATA_MAX 65536
- typedef struct {
- uint16_t p;
- uint8_t h;
- uint8_t o;
- uint8_t x;
- uint8_t y;
- uint8_t a;
- uint8_t d;
- uint8_t data[SSFN_DATA_MAX];
- } ssfn_glyph_t;
- typedef struct {
- uint8_t t;
- uint8_t n;
- uint8_t w;
- uint8_t h;
- uint8_t x;
- uint8_t y;
- } ssfn_chr_t;
- #ifdef SSFN_PROFILING
- #include <string.h>
- #include <sys/time.h>
- #endif
- typedef struct {
- #ifdef SSFN_MAXLINES
- const ssfn_font_t *fnt[5][16];
- #else
- const ssfn_font_t **fnt[5];
- #endif
- const ssfn_font_t *s;
- const ssfn_font_t *f;
- ssfn_glyph_t ga;
- ssfn_glyph_t *g;
- #ifdef SSFN_MAXLINES
- uint16_t p[SSFN_MAXLINES*2];
- #else
- ssfn_glyph_t ***c[17];
- uint16_t *p;
- char **bufs;
- #endif
- ssfn_chr_t *rc;
- int numbuf, lenbuf, np, ap, ox, oy, ax;
- int mx, my, lx, ly;
- int len[5];
- int family;
- int style;
- int size;
- int line;
- #ifdef SSFN_PROFILING
- uint64_t lookup, raster, blit, kern;
- #endif
- } ssfn_t;
- uint32_t ssfn_utf8(char **str);
- int ssfn_load(ssfn_t *ctx, const void *data);
- int ssfn_select(ssfn_t *ctx, int family, const char *name, int style, int size);
- int ssfn_render(ssfn_t *ctx, ssfn_buf_t *dst, const char *str);
- int ssfn_bbox(ssfn_t *ctx, const char *str, int *w, int *h, int *left, int *top);
- ssfn_buf_t *ssfn_text(ssfn_t *ctx, const char *str, unsigned int fg);
- int ssfn_mem(ssfn_t *ctx);
- void ssfn_free(ssfn_t *ctx);
- #define ssfn_error(err) (err<0&&err>=-7?ssfn_errstr[-err]:"Unknown error")
- extern const char *ssfn_errstr[];
- extern ssfn_font_t *ssfn_src;
- extern ssfn_buf_t ssfn_dst;
- int ssfn_putc(uint32_t unicode);
- #if (defined(SSFN_IMPLEMENTATION) || defined(SSFN_CONSOLEBITMAP_PALETTE) || \
- defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR)) && !defined(SSFN_COMMON)
- #define SSFN_COMMON
- const char *ssfn_errstr[] = { "",
- "Memory allocation error",
- "Bad file format",
- "No font face found",
- "Invalid input value",
- "Invalid style",
- "Invalid size",
- "Glyph not found"
- };
- uint32_t ssfn_utf8(char **s)
- {
- uint32_t c = **s;
- if((**s & 128) != 0) {
- if(!(**s & 32)) { c = ((**s & 0x1F)<<6)|(*(*s+1) & 0x3F); *s += 1; } else
- if(!(**s & 16)) { c = ((**s & 0xF)<<12)|((*(*s+1) & 0x3F)<<6)|(*(*s+2) & 0x3F); *s += 2; } else
- if(!(**s & 8)) { c = ((**s & 0x7)<<18)|((*(*s+1) & 0x3F)<<12)|((*(*s+2) & 0x3F)<<6)|(*(*s+3) & 0x3F); *s += 3; }
- else c = 0;
- }
- (*s)++;
- return c;
- }
- #endif
- #ifdef SSFN_IMPLEMENTATION
- # ifndef NULL
- # define NULL (void*)0
- # endif
- # ifndef size_t
- typedef __SIZE_TYPE__ size_t;
- # endif
- # ifndef inline
- # define inline __inline__
- # endif
- #ifndef _STRING_H_
- extern int memcmp (const void *__s1, const void *__s2, size_t __n) __THROW;
- extern void *memset (void *__s, int __c, size_t __n) __THROW;
- #endif
- # ifndef SSFN_memcmp
- # ifdef __builtin_memcmp
- # define SSFN_memcmp __builtin_memcmp
- # else
- # ifndef SSFN_MAXLINES
- # define SSFN_memcmp memcmp
- # else
- static int SSFN_memcmp(const void *__s1, const void *__s2, size_t __n)
- { unsigned char *a = (unsigned char *)__s1, *b = (unsigned char *)__s2;
- if(__n > 0) { while(__n-- > 0) { if(*a != *b) { return *a - *b; } a++; b++; } } return 0; }
- # endif
- # endif
- # endif
- # ifndef SSFN_memset
- # ifdef __builtin_memset
- # define SSFN_memset __builtin_memset
- # else
- # ifndef SSFN_MAXLINES
- # define SSFN_memset memset
- # else
- static void *SSFN_memset(void *__s, int __c, size_t __n)
- { unsigned char *a = __s; if(__n > 0) { while(__n-- > 0) *a++ = __c; } return __s; }
- # endif
- # endif
- # endif
- # ifndef SSFN_MAXLINES
- # ifndef SSFN_realloc
- # ifdef __builtin_realloc
- # define SSFN_realloc __builtin_realloc
- # else
- # define SSFN_realloc realloc
- extern void *realloc (void *__ptr, size_t __size) __THROW;
- # endif
- # endif
- # ifndef SSFN_free
- # ifdef __builtin_free
- # define SSFN_free __builtin_free
- # else
- # define SSFN_free free
- extern void free (void *p) __THROW;
- # endif
- # endif
- # endif
- static uint8_t *_ssfn_c(const ssfn_font_t *font, const char *str, int *len, uint32_t *unicode)
- {
- uint32_t i, j, u = -1U;
- uint16_t *l;
- uint8_t *ptr, *s;
- *len = 0; *unicode = 0;
- if(!font || !font->characters_offs || !str || !*str) return NULL;
- if(font->ligature_offs) {
- for(l = (uint16_t*)((uint8_t*)font + font->ligature_offs), i = 0; l[i] && u == -1U; i++) {
- for(ptr = (uint8_t*)font + l[i], s = (uint8_t*)str; *ptr && *ptr == *s; ptr++, s++);
- if(!*ptr) { u = SSFN_LIG_FIRST + i; break; }
- }
- }
- if(u == -1U) {
- s = (uint8_t*)str; u = *s;
- if((*s & 128) != 0) {
- if(!(*s & 32)) { u = ((*s & 0x1F)<<6)|(*(s+1) & 0x3F); s++; } else
- if(!(*s & 16)) { u = ((*s & 0xF)<<12)|((*(s+1) & 0x3F)<<6)|(*(s+2) & 0x3F); s += 2; } else
- if(!(*s & 8)) { u = ((*s & 0x7)<<18)|((*(s+1) & 0x3F)<<12)|((*(s+2) & 0x3F)<<6)|(*(s+3) & 0x3F); s += 3; }
- else u = 0;
- }
- s++;
- }
- *len = (int)(s - (uint8_t*)str);
- *unicode = u;
- for(ptr = (uint8_t*)font + font->characters_offs, i = 0; i < 0x110000; i++) {
- if(ptr[0] == 0xFF) { i += 65535; ptr++; }
- else if((ptr[0] & 0xC0) == 0xC0) { j = (((ptr[0] & 0x3F) << 8) | ptr[1]); i += j; ptr += 2; }
- else if((ptr[0] & 0xC0) == 0x80) { j = (ptr[0] & 0x3F); i += j; ptr++; }
- else {
- if(i == u) return ptr;
- ptr += 6 + ptr[1] * (ptr[0] & 0x40 ? 6 : 5);
- }
- }
- return NULL;
- }
- static void _ssfn_l(ssfn_t *ctx, int p, int h, int x, int y)
- {
- if(x < 0 || y < 0 || x >= p || y >= h || (
- ((ctx->lx + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((x + (1 << (SSFN_PREC-1))) >> SSFN_PREC) &&
- ((ctx->ly + (1 << (SSFN_PREC-1))) >> SSFN_PREC) == ((y + (1 << (SSFN_PREC-1))) >> SSFN_PREC))) return;
- #ifdef SSFN_MAXLINES
- if(ctx->np >= SSFN_MAXLINES*2-2) return;
- #else
- if(ctx->ap <= ctx->np) {
- ctx->ap = ctx->np + 512;
- ctx->p = (uint16_t*)SSFN_realloc(ctx->p, ctx->ap * sizeof(uint16_t));
- if(!ctx->p) { ctx->ap = ctx->np = 0; return; }
- }
- #endif
- if(!ctx->np) {
- ctx->p[0] = ctx->mx;
- ctx->p[1] = ctx->my;
- ctx->np += 2;
- }
- ctx->p[ctx->np+0] = x;
- ctx->p[ctx->np+1] = y;
- ctx->np += 2;
- ctx->lx = x; ctx->ly = y;
- }
- static void _ssfn_b(ssfn_t *ctx, int p,int h, int x0,int y0, int x1,int y1, int x2,int y2, int x3,int y3, int l)
- {
- int m0x, m0y, m1x, m1y, m2x, m2y, m3x, m3y, m4x, m4y,m5x, m5y;
- if(l<4 && (x0!=x3 || y0!=y3)) {
- m0x = ((x1-x0)/2) + x0; m0y = ((y1-y0)/2) + y0;
- m1x = ((x2-x1)/2) + x1; m1y = ((y2-y1)/2) + y1;
- m2x = ((x3-x2)/2) + x2; m2y = ((y3-y2)/2) + y2;
- m3x = ((m1x-m0x)/2) + m0x; m3y = ((m1y-m0y)/2) + m0y;
- m4x = ((m2x-m1x)/2) + m1x; m4y = ((m2y-m1y)/2) + m1y;
- m5x = ((m4x-m3x)/2) + m3x; m5y = ((m4y-m3y)/2) + m3y;
- _ssfn_b(ctx, p,h, x0,y0, m0x,m0y, m3x,m3y, m5x,m5y, l+1);
- _ssfn_b(ctx, p,h, m5x,m5y, m4x,m4y, m2x,m2y, x3,y3, l+1);
- }
- if(l) _ssfn_l(ctx, p,h, x3, y3);
- }
- int ssfn_load(ssfn_t *ctx, const void *data)
- {
- const ssfn_font_t *font = (const ssfn_font_t *)data;
- ssfn_font_t *fnt, *end;
- int family;
- if(!ctx || !font)
- return SSFN_ERR_INVINP;
- if(((uint8_t *)font)[0] == 0x1f && ((uint8_t *)font)[1] == 0x8b) {
- #ifdef SSFN_MAXLINES
- return SSFN_ERR_BADFILE;
- #else
- ptr += 2;
- if(*ptr++ != 8) return SSFN_ERR_BADFILE;
- c = *ptr++; ptr += 6;
- if(c & 4) { r = *ptr++; r += (*ptr++ << 8); ptr += r; }
- if(c & 8) { while(*ptr++ != 0); }
- if(c & 16) { while(*ptr++ != 0); }
- font = (ssfn_font_t*)_ssfn_zlib_decode((const char*)ptr);
- if(!font) return SSFN_ERR_BADFILE;
- ctx->bufs = (char**)SSFN_realloc(ctx->bufs, (ctx->numbuf + 1) * sizeof(char*));
- if(!ctx->bufs) { ctx->numbuf = 0; return SSFN_ERR_ALLOC; }
- ctx->bufs[ctx->numbuf++] = (char*)font;
- ctx->lenbuf += font->size;
- #endif
- }
- if(!SSFN_memcmp(font->magic, SSFN_COLLECTION, 4)) {
- end = (ssfn_font_t*)((uint8_t*)font + font->size);
- for(fnt = (ssfn_font_t*)((uint8_t*)font + 8); fnt < end && !ssfn_load(ctx, (const void *)fnt);
- fnt = (ssfn_font_t*)((uint8_t*)fnt + fnt->size));
- } else {
- family = SSFN_TYPE_FAMILY(font->type);
- if(SSFN_memcmp(font->magic, SSFN_MAGIC, 4) || SSFN_memcmp((uint8_t*)font + font->size - 4, SSFN_ENDMAGIC, 4) ||
- family > SSFN_FAMILY_HAND || font->fragments_offs >= font->size || font->characters_offs >= font->size ||
- font->ligature_offs >= font->size || font->kerning_offs >= font->size || font->cmap_offs >= font->size ||
- font->fragments_offs >= font->characters_offs) {
- return SSFN_ERR_BADFILE;
- } else {
- ctx->len[family]++;
- #ifdef SSFN_MAXLINES
- if(ctx->len[family] > 15) return SSFN_ERR_ALLOC;
- #else
- ctx->fnt[family] = (const ssfn_font_t**)SSFN_realloc(ctx->fnt[family], ctx->len[family]*sizeof(void*));
- if(!ctx->fnt[family]) {
- ctx->len[family] = 0;
- return SSFN_ERR_ALLOC;
- } else
- #endif
- ctx->fnt[family][ctx->len[family]-1] = font;
- }
- }
- return SSFN_OK;
- }
- void ssfn_free(ssfn_t *ctx)
- {
- if(!ctx) return;
- SSFN_memset(ctx, 0, sizeof(ssfn_t));
- }
- int ssfn_mem(ssfn_t *ctx)
- {
- #ifdef SSFN_MAXLINES
- return ctx ? sizeof(ssfn_t) : 0;
- #else
- int i, j, k, ret = sizeof(ssfn_t);
- if(!ctx) return 0;
- for(i = 0; i < 5; i++) ret += ctx->len[i] * sizeof(ssfn_font_t*);
- ret += ctx->lenbuf;
- for(k = 0; k <= 16; k++) {
- if(ctx->c[k]) {
- for(j = 0; j < 256; j++)
- if(ctx->c[k][j]) {
- for(i = 0; i < 256; i++)
- if(ctx->c[k][j][i]) ret += 8 + ctx->c[k][j][i]->p * ctx->c[k][j][i]->h;
- ret += 256 * sizeof(void*);
- }
- ret += 256 * sizeof(void*);
- }
- }
- if(ctx->p) ret += ctx->ap * sizeof(uint16_t);
- return ret;
- #endif
- }
- int ssfn_select(ssfn_t *ctx, int family, const char *name, int style, int size)
- {
- int i, j, l;
- if(!ctx) return SSFN_ERR_INVINP;
- if((style & ~0x5FFF)) return SSFN_ERR_BADSTYLE;
- if(size < 8 || size > SSFN_SIZE_MAX) return SSFN_ERR_BADSIZE;
- if(family == SSFN_FAMILY_BYNAME) {
- if(!name || !name[0]) return SSFN_ERR_INVINP;
- for(l=0; name[l]; l++);
- for(i=0; i < 5; i++) {
- for(j=0; j < ctx->len[i]; j++) {
- if(!SSFN_memcmp(name, (uint8_t*)&ctx->fnt[i][j]->magic + sizeof(ssfn_font_t), l)) {
- ctx->s = ctx->fnt[i][j];
- goto familyfound;
- }
- }
- }
- return SSFN_ERR_NOFACE;
- } else {
- if(family != SSFN_FAMILY_ANY && (family > SSFN_FAMILY_HAND || !ctx->len[family])) return SSFN_ERR_NOFACE;
- ctx->s = NULL;
- }
- familyfound:
- ctx->f = NULL;
- ctx->family = family;
- ctx->style = style;
- ctx->size = size;
- ctx->line = 0;
- return SSFN_OK;
- }
- int ssfn_render(ssfn_t *ctx, ssfn_buf_t *dst, const char *str)
- {
- ssfn_font_t **fl;
- uint8_t *ptr = NULL, *frg, *end, *tmp, color, ci = 0, cb = 0, cs, dec[65536];
- uint16_t r[640];
- uint32_t unicode, P, O, *Op, *Ol, sR, sG, sB, sA, bA;
- int ret = 0, i, j, k, l, p, m, n, o, s, x, y, w, h, H, a, A, b, B, nr, uix, uax;
- int ox, oy, y0, y1, Y0, Y1, x0, x1, X0, X1, X2, xs, ys, yp, pc, fB, fG, fR, fA, bB, bG, bR, dB, dG, dR, dA;
- #ifdef SSFN_PROFILING
- struct timeval tv0, tv1, tvd;
- gettimeofday(&tv0, NULL);
- #endif
- #define PUTPIXEL O = *Ol;bR = (O >> (16 - cs)) & 0xFF; bG = (O >> 8) & 0xFF; bB = (O >> cs) & 0xFF; bA = (O >> 24) & 0xFF;\
- bB += ((fB - bB) * fA) >> 8; bG += ((fG - bG) * fA) >> 8; bR += ((fR - bR) * fA) >> 8; bA += ((fA - bA) * fA) >> 8;\
- *Ol = (bA << 24) | (bR << (16 - cs)) | (bG << 8) | (bB << cs);
- if(!ctx || !str) return SSFN_ERR_INVINP;
- if(!*str) return 0;
- if(*str == '\r') { dst->x = 0; return 1; }
- if(*str == '\n') { dst->x = 0; dst->y += ctx->line ? ctx->line : ctx->size; return 1; }
- if(ctx->s) {
- ctx->f = ctx->s;
- ptr = _ssfn_c(ctx->f, str, &ret, &unicode);
- } else {
- p = ctx->family;
- ctx->f = NULL;
- again: if(p >= SSFN_FAMILY_BYNAME) { n = 0; m = 4; } else n = m = p;
- for(; n <= m; n++) {
- fl = (ssfn_font_t **)ctx->fnt[n];
- if(ctx->style & 3) {
- for(i=0;i<ctx->len[n];i++)
- if(((fl[i]->type>>4) & 3) == (ctx->style & 3) && fl[i]->height == ctx->size &&
- (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; }
- if(!ptr)
- for(i=0;i<ctx->len[n];i++)
- if(fl[i]->height == ctx->size && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; }
- if(!ptr)
- for(i=0;i<ctx->len[n];i++)
- if(((fl[i]->type>>4) & 3) == (ctx->style & 3) && (ptr = _ssfn_c(fl[i], str, &ret, &unicode)))
- { ctx->f = fl[i]; break; }
- if(!ptr && (ctx->style & 3) == 3)
- for(i=0;i<ctx->len[n];i++)
- if(((fl[i]->type>>4) & 3) && (ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; }
- }
- if(!ptr) {
- for(i=0;i<ctx->len[n];i++)
- if((ptr = _ssfn_c(fl[i], str, &ret, &unicode))) { ctx->f = fl[i]; break; }
- }
- }
- if(!ptr && p != SSFN_FAMILY_ANY) { p = SSFN_FAMILY_ANY; goto again; }
- }
- if(!ptr) {
- if(ctx->style & SSFN_STYLE_NODEFGLYPH) return SSFN_ERR_NOGLYPH;
- else {
- unicode = 0;
- if(ctx->family >= SSFN_FAMILY_BYNAME) { n = 0; m = 4; } else n = m = ctx->family;
- for(; n <= m && !ptr; n++)
- if(ctx->len[n] && ctx->fnt[n][0] && !(*((uint8_t*)ctx->fnt[n][0] + ctx->fnt[n][0]->characters_offs) & 0x80))
- { ctx->f = ctx->fnt[n][0]; ptr = (uint8_t*)ctx->f + ctx->f->characters_offs; }
- }
- if(!ptr) return SSFN_ERR_NOGLYPH;
- }
- if(!ctx->f || !ctx->f->height || !ctx->size) return SSFN_ERR_NOFACE;
- if((unicode >> 16) > 0x10) return SSFN_ERR_INVINP;
- ctx->rc = (ssfn_chr_t*)ptr; ptr += sizeof(ssfn_chr_t);
- H = (ctx->style & SSFN_STYLE_ABS_SIZE) || SSFN_TYPE_FAMILY(ctx->f->type) == SSFN_FAMILY_MONOSPACE || !ctx->f->baseline ?
- ctx->size : ctx->size * ctx->f->height / ctx->f->baseline;
- #ifdef SSFN_PROFILING
- gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
- if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
- ctx->lookup += tvd.tv_sec * 1000000L + tvd.tv_usec;
- memcpy(&tv0, &tv1, sizeof(struct timeval));
- #endif
- {
- h = ctx->style & SSFN_STYLE_NOAA ? H : (ctx->size > ctx->f->height ? (ctx->size + 4) & ~3 : ctx->f->height);
- ci = (ctx->style & SSFN_STYLE_ITALIC) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_ITALIC);
- cb = (ctx->style & SSFN_STYLE_BOLD) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_BOLD) ? (ctx->f->height+64)>>6 : 0;
- w = (ctx->rc->w * h + ctx->f->height - 1) / ctx->f->height;
- if(w > SSFN_SIZE_MAX) { h = h * SSFN_SIZE_MAX / w; w = SSFN_SIZE_MAX; }
- p = w + (ci ? h / SSFN_ITALIC_DIV : 0) + cb;
- if(p * h >= SSFN_DATA_MAX) return SSFN_ERR_BADSIZE;
- ctx->g = &ctx->ga;
- x = (ctx->rc->x > 0 && ci ? (ctx->f->height - ctx->f->baseline) * h / SSFN_ITALIC_DIV / ctx->f->height : 0);
- ctx->g->p = p;
- ctx->g->h = h;
- ctx->g->x = (ctx->rc->x + x > 255 ? 255 : ctx->rc->x + x);
- ctx->g->y = ctx->rc->y;
- ctx->g->o = (ctx->rc->t & 0x3F) + x;
- SSFN_memset(&ctx->g->data, 0xFF, p * h);
- color = 0xFE; ctx->g->a = ctx->g->d = 0;
- for(n = 0; n < ctx->rc->n; n++) {
- if(ptr[0] == 255 && ptr[1] == 255) { color = ptr[2]; ptr += ctx->rc->t & 0x40 ? 6 : 5; continue; }
- x = ((ptr[0] + cb) << SSFN_PREC) * h / ctx->f->height; y = (ptr[1] << SSFN_PREC) * h / ctx->f->height;
- if(ctx->rc->t & 0x40) { m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 6; }
- else { m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 5; }
- frg = (uint8_t*)ctx->f + m;
- if(!(frg[0] & 0x80)) {
- j = (frg[0] & 0x3F);
- if(frg[0] & 0x40) { j <<= 8; j |= frg[1]; frg++; }
- j++; frg++; tmp = frg; frg += (j+3)/4; ctx->np = 0;
- for(i = 0; i < j; i++) {
- k = (frg[0] << SSFN_PREC) * h / ctx->f->height + x; m = (frg[1] << SSFN_PREC) * h / ctx->f->height + y;
- switch((tmp[i >> 2] >> ((i & 3) << 1)) & 3) {
- case SSFN_CONTOUR_MOVE: ctx->mx = ctx->lx = k; ctx->my = ctx->ly = m; frg += 2; break;
- case SSFN_CONTOUR_LINE: _ssfn_l(ctx, p << SSFN_PREC, h << SSFN_PREC, k, m); frg += 2; break;
- case SSFN_CONTOUR_QUAD:
- a = (frg[2] << SSFN_PREC) * h / ctx->f->height + x; A = (frg[3] << SSFN_PREC) * h / ctx->f->height + y;
- _ssfn_b(ctx, p << SSFN_PREC,h << SSFN_PREC, ctx->lx,ctx->ly, ((a-ctx->lx)/2)+ctx->lx,
- ((A-ctx->ly)/2)+ctx->ly, ((k-a)/2)+a,((A-m)/2)+m, k,m, 0);
- frg += 4;
- break;
- case SSFN_CONTOUR_CUBIC:
- a = (frg[2] << SSFN_PREC) * h / ctx->f->height + x; A = (frg[3] << SSFN_PREC) * h / ctx->f->height + y;
- b = (frg[4] << SSFN_PREC) * h / ctx->f->height + x; B = (frg[5] << SSFN_PREC) * h / ctx->f->height + y;
- _ssfn_b(ctx, p << SSFN_PREC,h << SSFN_PREC, ctx->lx,ctx->ly, a,A, b,B, k,m, 0);
- frg += 6;
- break;
- }
- }
- if(ctx->mx != ctx->lx || ctx->my != ctx->ly) { ctx->p[ctx->np+0] = ctx->mx; ctx->p[ctx->np+1] = ctx->my; ctx->np += 2; }
- if(ctx->np > 4) {
- for(b = A = B = o = 0; b < h; b++, B += p) {
- a = b << SSFN_PREC;
- for(nr = 0, i = 0; i < ctx->np - 3; i += 2) {
- if( (ctx->p[i+1] < a && ctx->p[i+3] >= a) ||
- (ctx->p[i+3] < a && ctx->p[i+1] >= a)) {
- if((ctx->p[i+1] >> SSFN_PREC) == (ctx->p[i+3] >> SSFN_PREC))
- x = (((int)ctx->p[i]+(int)ctx->p[i+2])>>1);
- else
- x = ((int)ctx->p[i]) + ((a - (int)ctx->p[i+1])*
- ((int)ctx->p[i+2] - (int)ctx->p[i])/
- ((int)ctx->p[i+3] - (int)ctx->p[i+1]));
- x >>= SSFN_PREC;
- if(ci) x += (h - b) / SSFN_ITALIC_DIV;
- if(cb && !o) {
- if(ctx->g->data[B + x] != color) { o = -cb; A = cb; }
- else { o = cb; A = -cb; }
- }
- for(k = 0; k < nr && x > r[k]; k++);
- for(l = nr; l > k; l--) r[l] = r[l-1];
- r[k] = x;
- nr++;
- }
- }
- if(nr > 1 && nr & 1) { r[nr - 2] = r[nr - 1]; nr--; }
- if(nr) {
- if(ctx->g->d < y + b) ctx->g->d = y + b;
- for(i = 0; i < nr - 1; i += 2) {
- l = r[i] + o; m = r[i + 1] + A;
- if(l < 0) l = 0;
- if(m > p) m = p;
- if(i > 0 && l < r[i - 1] + A) l = r[i - 1] + A;
- for(; l < m; l++)
- ctx->g->data[B + l] = ctx->g->data[B + l] == color ? 0xFF : color;
- }
- }
- }
- }
- } else if((frg[0] & 0x60) == 0x00) {
- B = ((frg[0] & 0x1F) + 1) << 3; A = frg[1] + 1; x >>= SSFN_PREC; y >>= SSFN_PREC;
- b = B * h / ctx->f->height; a = A * h / ctx->f->height;
- if(ctx->g->d < y + a) ctx->g->d = y + a;
- frg += 2;
- for(j = 0; j < a; j++) {
- k = j * A / a;
- l = (y + j) * p + x + (ci ? (h - y - j) / SSFN_ITALIC_DIV : 0);
- for(i = 0; i < b; i++) {
- m = i * B / b;
- if(frg[(k * B + m) >> 3] & (1 << (m & 7))) {
- for(o = 0; o <= cb; o++)
- ctx->g->data[l + i + o] = color;
- }
- }
- }
- if(!(ctx->style & (SSFN_STYLE_NOAA|SSFN_STYLE_NOSMOOTH))) {
- m = color == 0xFD ? 0xFC : 0xFD; o = y * p + p + x;
- for(k = h; k > ctx->f->height + 4; k -= 2*ctx->f->height) {
- for(j = 1, l = o; j < a - 1; j++, l += p)
- for(i = 1; i < b - 1; i++) {
- if(ctx->g->data[l + i] == 0xFF && (ctx->g->data[l + i - p] == color ||
- ctx->g->data[l + i + p] == color) && (ctx->g->data[l + i - 1] == color ||
- ctx->g->data[l + i + 1] == color)) ctx->g->data[l + i] = m;
- }
- for(j = 1, l = o; j < a - 1; j++, l += p)
- for(i = 1; i < b - 1; i++) {
- if(ctx->g->data[l + i] == m) ctx->g->data[l + i] = color;
- }
- }
- }
- } else if((frg[0] & 0x60) == 0x20) {
- k = (((frg[0] & 0x1F) << 8) | frg[1]) + 1; B = frg[2] + 1; A = frg[3] + 1; x >>= SSFN_PREC; y >>= SSFN_PREC;
- b = B * h / ctx->f->height; a = A * h / ctx->f->height;
- if(ctx->g->d < y + a) ctx->g->d = y + a;
- frg += 4; end = frg + k; i = 0;
- while(frg < end) {
- l = ((*frg++) & 0x7F) + 1;
- if(frg[-1] & 0x80) {
- while(l--) dec[i++] = *frg;
- frg++;
- } else while(l--) dec[i++] = *frg++;
- }
- for(j = 0; j < a; j++) {
- k = j * A / a * B;
- l = (y + j) * p + x + (ci ? (h - y - j) / SSFN_ITALIC_DIV : 0);
- for(i = 0; i < b; i++) {
- m = dec[k + i * B / b];
- if(m != 0xFF) ctx->g->data[l + i] = m;
- }
- }
- }
- color = 0xFE;
- }
- ctx->g->a = ctx->f->baseline;
- if(ctx->g->d > ctx->g->a + 1) ctx->g->d -= ctx->g->a + 1; else ctx->g->d = 0;
- #ifdef SSFN_DEBUGGLYPH
- printf("\nU+%06X size %d p %d h %d base %d under %d overlap %d ascender %d descender %d advance x %d advance y %d cb %d\n",
- unicode, ctx->size,p,h,ctx->f->baseline,ctx->f->underline,ctx->g->o,ctx->g->a,ctx->g->d,ctx->g->x,ctx->g->y,cb);
- for(j = 0; j < h; j++) { printf("%3d: ", j); for(i = 0; i < p; i++) { if(ctx->g->data[j*p+i] == 0xFF) printf(j == ctx->g->a ? "_" : "."); else printf("%x", ctx->g->data[j*p+i] & 0xF); } printf("\n"); }
- #endif
- #ifdef SSFN_PROFILING
- gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
- if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
- ctx->raster += tvd.tv_sec * 1000000L + tvd.tv_usec;
- memcpy(&tv0, &tv1, sizeof(struct timeval));
- #endif
- }
- if(dst) {
- h = H;
- if(h > ctx->line) ctx->line = h;
- w = ctx->g->p * h / ctx->g->h;
- s = ((ctx->g->x - ctx->g->o) * h + ctx->f->height - 1) / ctx->f->height;
- n = ctx->size > 16 ? 2 : 1;
- if(w < n) w = n;
- if(s < n) s = n;
- if(ctx->g->x) {
- ctx->ox = ox = ((ctx->g->o * h + ctx->f->height - 1) / ctx->f->height) + (ctx->style & SSFN_STYLE_RTL ? w : 0);
- ctx->oy = oy = (ctx->g->a * h + ctx->f->height - 1) / ctx->f->height;
- } else { ctx->ox = ox = w / 2; ctx->oy = oy = 0; }
- if(dst->ptr) {
- j = dst->w < 0 ? -dst->w : dst->w;
- cs = dst->w < 0 ? 16 : 0;
- cb = (h + 64) >> 6; uix = w > s ? w : s; uax = 0;
- n = (ctx->f->underline * h + ctx->f->height - 1) / ctx->f->height;
- #ifdef SSFN_DEBUGGLYPH
- printf("Scaling to w %d h %d (glyph %d %d, cache %d %d, font %d)\n",
- w,h,ctx->rc->w,ctx->rc->h,ctx->g->p,ctx->g->h,ctx->f->height);
- #endif
- fR = (dst->fg >> 16) & 0xFF; fG = (dst->fg >> 8) & 0xFF; fB = (dst->fg >> 0) & 0xFF; fA = (dst->fg >> 24) & 0xFF;
- bR = (dst->bg >> 16) & 0xFF; bG = (dst->bg >> 8) & 0xFF; bB = (dst->bg >> 0) & 0xFF; O = 0xFF000000;
- Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy) + ((dst->x - ox) << 2));
- for (y = 0; y < h && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) {
- if(dst->y + y - oy < 0) continue;
- y0 = (y << 8) * ctx->g->h / h; Y0 = y0 >> 8; y1 = ((y + 1) << 8) * ctx->g->h / h; Y1 = y1 >> 8; Ol = Op;
- for (x = 0; x < w && dst->x + x - ox < j; x++, Ol++) {
- if(dst->x + x - ox < 0) continue;
- m = 0; sR = sG = sB = sA = bA = 0;
- if(!dst->bg) {
- O = *Ol;
- bA = (O >> 24) & 0xFF;
- bR = (O >> (16 - cs)) & 0xFF;
- bG = (O >> 8) & 0xFF;
- bB = (O >> cs) & 0xFF;
- }
- x0 = (x << 8) * ctx->g->p / w; X0 = x0 >> 8; x1 = ((x + 1) << 8) * ctx->g->p / w; X1 = x1 >> 8;
- for(ys = y0; ys < y1; ys += 256) {
- if(ys >> 8 == Y0) { yp = 256 - (ys & 0xFF); ys &= ~0xFF; if(yp > y1 - y0) yp = y1 - y0; }
- else if(ys >> 8 == Y1) yp = y1 & 0xFF; else yp = 256;
- X2 = (ys >> 8) * ctx->g->p;
- for(xs = x0; xs < x1; xs += 256) {
- if (xs >> 8 == X0) {
- k = 256 - (xs & 0xFF); xs &= ~0xFF; if(k > x1 - x0) k = x1 - x0; pc = k == 256 ? yp : (k * yp)>>8;
- } else
- if (xs >> 8 == X1) { k = x1 & 0xFF; pc = k == 256 ? yp : (k * yp) >> 8; }
- else pc = yp;
- m += pc;
- k = ctx->g->data[X2 + (xs >> 8)];
- if(k == 0xFF) {
- sB += bB * pc; sG += bG * pc; sR += bR * pc; sA += 255;
- } else {
- if(k == 0xFE || !ctx->f->cmap_offs) {
- dB = fB; dG = fG; dR = fR; dA = fA;
- } else {
- P = *((uint32_t*)((uint8_t*)ctx->f + ctx->f->cmap_offs + (k << 2)));
- dR = (P >> 16) & 0xFF; dG = (P >> 8) & 0xFF; dB = (P >> 0) & 0xFF; dA = (P >> 24) & 0xFF;
- }
- if(dA == 255) {
- sB += dB * pc; sG += dG * pc; sR += dR * pc; sA += dA * pc;
- } else {
- sB += (dB * dA + bB * (255 - dA)) * pc / 255; sG += (dG * dA + bG * (255 - dA)) * pc / 255;
- sR += (dR * dA + bR * (255 - dA)) * pc / 255; sA += dA * pc;
- }
- }
- }
- }
- if(m) { sR /= m; sG /= m; sB /= m; sA /= m; } else { sR >>= 8; sG >>= 8; sB >>= 8; sA >>= 8; }
- if(ctx->style & SSFN_STYLE_NOAA) sA = sA > 127 ? 255 : 0;
- if(sA > 15) {
- *Ol = ((sA > 255 ? 255 : (sA > bA ? sA : bA)) << 24) |
- ((sR > 255 ? 255 : sR) << (16 - cs)) | ((sG > 255 ? 255 : sG) << 8) | ((sB > 255 ? 255 : sB) << cs);
- if(y == n) { if(uix > x) { uix = x; } if(uax < x) { uax = x; } }
- }
- }
- }
- if(ctx->style & SSFN_STYLE_UNDERLINE) {
- uix -= cb + 1; uax += cb + 2;
- if(uax < uix) uax = uix + 1;
- k = (w > s ? w : s);
- Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy + n) + ((dst->x - ox - 1) << 2));
- for (y = n; y < n + cb && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) {
- if(dst->y + y - oy < 0) continue;
- for (Ol = Op, x = 0; x <= k && dst->x + x - ox < j; x++, Ol++) {
- if(dst->x + x - ox < 0 || (x > uix && x < uax)) continue;
- PUTPIXEL;
- }
- }
- }
- if(ctx->style & SSFN_STYLE_STHROUGH) {
- n = (h >> 1); k = (w > s ? w : s) + 1;
- Op = (uint32_t*)(dst->ptr + dst->p * (dst->y - oy + n) + ((dst->x - ox - 1) << 2));
- for (y = n; y < n + cb && dst->y + y - oy < dst->h; y++, Op += dst->p >> 2) {
- if(dst->y + y - oy < 0) continue;
- for (Ol = Op, x = 0; x <= k && dst->x + x - ox < j; x++, Ol++) {
- if(dst->x + x - ox < 0) continue;
- PUTPIXEL;
- }
- }
- }
- #ifdef SSFN_PROFILING
- gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec;tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
- if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
- ctx->blit += tvd.tv_sec * 1000000L + tvd.tv_usec;
- memcpy(&tv0, &tv1, sizeof(struct timeval));
- #endif
- }
- ctx->ax = (ctx->style & SSFN_STYLE_RTL ? -s : s);
- dst->x += ctx->ax;
- dst->y += (ctx->g->y * h + ctx->f->height - 1) / ctx->f->height;
- ptr = (uint8_t*)str + ret;
- if(!(ctx->style & SSFN_STYLE_NOKERN) && ctx->f->kerning_offs && _ssfn_c(ctx->f, (const char*)ptr, &i, &P) && P > 32) {
- ptr = (uint8_t*)ctx->rc + sizeof(ssfn_chr_t);
- for(n = 0; n < ctx->rc->n; n++) {
- if(ptr[0] == 255 && ptr[1] == 255) { ptr += ctx->rc->t & 0x40 ? 6 : 5; continue; }
- x = ptr[0];
- if(ctx->rc->t & 0x40) { m = (ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 6; }
- else { m = (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]; ptr += 5; }
- frg = (uint8_t*)ctx->f + m;
- if((frg[0] & 0xE0) == 0xC0) {
- k = (((frg[0] & 0x1F) << 8) | frg[1]) + 1; frg += 2;
- while(k--) {
- m = ((frg[2] & 0xF) << 16) | (frg[1] << 8) | frg[0];
- if(P >= (uint32_t)m && P <= (uint32_t)(((frg[5] & 0xF) << 16) | (frg[4] << 8) | frg[3])) {
- P -= m;
- m = ctx->f->kerning_offs + ((((frg[2] >> 4) & 0xF) << 24) | (((frg[5] >> 4) & 0xF) << 16) |
- (frg[7] << 8) | frg[6]);
- tmp = (uint8_t*)ctx->f + m;
- while(tmp < (uint8_t*)ctx->f + ctx->f->size - 4) {
- if((tmp[0] & 0x7F) < P) {
- P -= (tmp[0] & 0x7F) + 1;
- tmp += 2 + (tmp[0] & 0x80 ? 0 : tmp[0] & 0x7F);
- } else {
- y = (int)((signed char)tmp[1 + ((tmp[0] & 0x80) ? 0 : P)]) * h / ctx->f->height;
- if(x) dst->x += y; else dst->y += y;
- break;
- }
- }
- break;
- }
- frg += 8;
- }
- }
- }
- #ifdef SSFN_PROFILING
- gettimeofday(&tv1, NULL); tvd.tv_sec = tv1.tv_sec - tv0.tv_sec; tvd.tv_usec = tv1.tv_usec - tv0.tv_usec;
- if(tvd.tv_usec < 0) { tvd.tv_sec--; tvd.tv_usec += 1000000L; }
- ctx->kern += tvd.tv_sec * 1000000L + tvd.tv_usec;
- #endif
- }
- }
- return ret;
- }
- int ssfn_bbox(ssfn_t *ctx, const char *str, int *w, int *h, int *left, int *top)
- {
- ssfn_buf_t buf;
- int ret, f = 1, l = 0, t = 0;
- if(!ctx || !str) return SSFN_ERR_INVINP;
- if(w) {*w = 0;} if(h) {*h = 0;} if(top) {*top = 0;} if(left) {*left = 0;}
- if(!*str) return SSFN_OK;
- SSFN_memset(&buf, 0, sizeof(ssfn_buf_t)); ctx->line = 0;
- while((ret = ssfn_render(ctx, &buf, str))) {
- if(ret < 0 || !ctx->g) return ret;
- if(f) { f = 0; l = ctx->ox; buf.x += l; }
- if(ctx->g->x) {
- if(ctx->oy > t) t = ctx->oy;
- } else {
- if(buf.w < ctx->g->p) buf.w = ctx->g->p;
- buf.h += ctx->g->y ? ctx->g->y : ctx->g->h;
- }
- str += ret;
- }
- if((ctx->style & SSFN_STYLE_ITALIC) && !(SSFN_TYPE_STYLE(ctx->f->type) & SSFN_STYLE_ITALIC))
- buf.x += ctx->size / SSFN_ITALIC_DIV - l;
- if(ctx->g->x) { if(w) {*w = buf.x;} if(h) {*h = ctx->line;} if(left) {*left = l;} if(top) {*top = t;} }
- else { if(w) {*w = buf.w;} if(h) {*h = buf.y;} if(top) {*top = 0;} if(left) {*left = 0;} }
- return SSFN_OK;
- }
- ssfn_buf_t *ssfn_text(ssfn_t *ctx, const char *str, unsigned int fg)
- {
- (void)ctx;
- (void)str;
- (void)fg;
- return NULL;
- }
- #endif
- #if defined(SSFN_CONSOLEBITMAP_PALETTE) || defined(SSFN_CONSOLEBITMAP_HICOLOR) || defined(SSFN_CONSOLEBITMAP_TRUECOLOR)
- ssfn_font_t *ssfn_src;
- ssfn_buf_t ssfn_dst;
- int ssfn_putc(uint32_t unicode)
- {
- # ifdef SSFN_CONSOLEBITMAP_PALETTE
- # define SSFN_PIXEL uint8_t
- # else
- # ifdef SSFN_CONSOLEBITMAP_HICOLOR
- # define SSFN_PIXEL uint16_t
- # else
- # define SSFN_PIXEL uint32_t
- # endif
- # endif
- register SSFN_PIXEL *o, *p;
- register uint8_t *ptr, *chr = NULL, *frg;
- register int i, j, k, l, m, y = 0, w, s = ssfn_dst.p / sizeof(SSFN_PIXEL);
- if(!ssfn_src || ssfn_src->magic[0] != 'S' || ssfn_src->magic[1] != 'F' || ssfn_src->magic[2] != 'N' ||
- ssfn_src->magic[3] != '2' || !ssfn_dst.ptr || !ssfn_dst.p) return SSFN_ERR_INVINP;
- w = ssfn_dst.w < 0 ? -ssfn_dst.w : ssfn_dst.w;
- for(ptr = (uint8_t*)ssfn_src + ssfn_src->characters_offs, i = 0; i < 0x110000; i++) {
- if(ptr[0] == 0xFF) { i += 65535; ptr++; }
- else if((ptr[0] & 0xC0) == 0xC0) { j = (((ptr[0] & 0x3F) << 8) | ptr[1]); i += j; ptr += 2; }
- else if((ptr[0] & 0xC0) == 0x80) { j = (ptr[0] & 0x3F); i += j; ptr++; }
- else { if((uint32_t)i == unicode) { chr = ptr; break; } ptr += 6 + ptr[1] * (ptr[0] & 0x40 ? 6 : 5); }
- }
- #ifdef SSFN_CONSOLEBITMAP_CONTROL
- i = ssfn_src->height; j = ssfn_dst.h - i - (ssfn_dst.h % i);
- if(chr && w) {
- if(unicode == '\t') ssfn_dst.x -= ssfn_dst.x % chr[4];
- if(ssfn_dst.x + chr[4] > w) { ssfn_dst.x = 0; ssfn_dst.y += i; }
- }
- if(unicode == '\n') ssfn_dst.y += i;
- if(j > 0 && ssfn_dst.y > j) {
- ssfn_dst.y = j;
- for(k = 0; k < j; k++)
- for(l = 0; l < ssfn_dst.p; l++) ssfn_dst.ptr[k * ssfn_dst.p + l] = ssfn_dst.ptr[(k + i) * ssfn_dst.p + l];
- }
- if(unicode == '\r' || unicode == '\n') { ssfn_dst.x = 0; return SSFN_OK; }
- #endif
- if(!chr) return SSFN_ERR_NOGLYPH;
- ptr = chr + 6; o = (SSFN_PIXEL*)(ssfn_dst.ptr + ssfn_dst.y * ssfn_dst.p + ssfn_dst.x * sizeof(SSFN_PIXEL));
- for(i = 0; i < chr[1]; i++, ptr += chr[0] & 0x40 ? 6 : 5) {
- if(ptr[0] == 255 && ptr[1] == 255) continue;
- frg = (uint8_t*)ssfn_src + (chr[0] & 0x40 ? ((ptr[5] << 24) | (ptr[4] << 16) | (ptr[3] << 8) | ptr[2]) :
- ((ptr[4] << 16) | (ptr[3] << 8) | ptr[2]));
- if((frg[0] & 0xE0) != 0x80) continue;
- if(ssfn_dst.bg) {
- for(; y < ptr[1] && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); y++, o += s) {
- for(p = o, j = 0; j < chr[2] && (!w || ssfn_dst.x + j < w); j++, p++)
- *p = ssfn_dst.bg;
- }
- } else { o += (int)(ptr[1] - y) * s; y = ptr[1]; }
- k = ((frg[0] & 0x1F) + 1) << 3; j = frg[1] + 1; frg += 2;
- for(m = 1; j && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); j--, y++, o += s)
- for(p = o, l = 0; l < k; l++, p++, m <<= 1) {
- if(m > 0x80) { frg++; m = 1; }
- if(ssfn_dst.x + l >= 0 && (!w || ssfn_dst.x + l < w)) {
- if(*frg & m) *p = ssfn_dst.fg; else
- if(ssfn_dst.bg) *p = ssfn_dst.bg;
- }
- }
- }
- if(ssfn_dst.bg)
- for(; y < chr[3] && (!ssfn_dst.h || ssfn_dst.y + y < ssfn_dst.h); y++, o += s) {
- for(p = o, j = 0; j < chr[2] && (!w || ssfn_dst.x + j < w); j++, p++)
- *p = ssfn_dst.bg;
- }
- ssfn_dst.x += chr[4]; ssfn_dst.y += chr[5];
- return SSFN_OK;
- }
- #endif
- #endif
- #if !defined(M3D_HEADERONLY) && !defined(M3D_IMPLEMENTATION)
- #define M3D_IMPLEMENTATION
- #define M3D_NOTEXTURE
- #endif
- #endif /* APCK_IMPLEMENTATION */
- /* m3d.h - Model3D - MIT license
- https://bztsrc.gitlab.com/model3d */
- /**************** embeded m3d.h ****************/
- #ifndef _M3D_H_
- #define _M3D_H_
- #include <stdint.h>
- #ifndef M3D_MALLOC
- # define M3D_MALLOC(sz) malloc(sz)
- #endif
- #ifndef M3D_REALLOC
- # define M3D_REALLOC(p,nsz) realloc(p,nsz)
- #endif
- #ifndef M3D_FREE
- # define M3D_FREE(p) free(p)
- #endif
- #ifndef M3D_LOG
- # define M3D_LOG(x)
- #endif
- #ifndef M3D_APIVERSION
- #define M3D_APIVERSION 0x0100
- #ifndef M3D_DOUBLE
- typedef float M3D_FLOAT;
- #ifndef M3D_EPSILON
- #define M3D_EPSILON ((M3D_FLOAT)1e-7)
- #endif
- #else
- typedef double M3D_FLOAT;
- #ifndef M3D_EPSILON
- #define M3D_EPSILON ((M3D_FLOAT)1e-14)
- #endif
- #endif
- #if !defined(M3D_SMALLINDEX)
- typedef uint32_t M3D_INDEX;
- typedef uint16_t M3D_VOXEL;
- #define M3D_UNDEF 0xffffffff
- #define M3D_INDEXMAX 0xfffffffe
- #define M3D_VOXUNDEF 0xffff
- #define M3D_VOXCLEAR 0xfffe
- #else
- typedef uint16_t M3D_INDEX;
- typedef uint8_t M3D_VOXEL;
- #define M3D_UNDEF 0xffff
- #define M3D_INDEXMAX 0xfffe
- #define M3D_VOXUNDEF 0xff
- #define M3D_VOXCLEAR 0xfe
- #endif
- #define M3D_NOTDEFINED 0xffffffff
- #ifndef M3D_NUMBONE
- #define M3D_NUMBONE 4
- #endif
- #ifndef M3D_BONEMAXLEVEL
- #define M3D_BONEMAXLEVEL 64
- #endif
- #ifndef _MSC_VER
- #ifndef _inline
- #define _inline __inline__
- #endif
- #define _pack __attribute__((packed))
- #define _unused __attribute__((unused))
- #else
- #define _inline
- #define _pack
- #define _unused __pragma(warning(suppress:4100))
- #endif
- #ifndef __cplusplus
- #define _register register
- #else
- #define _register
- #endif
- #ifdef _MSC_VER
- #pragma pack(push)
- #pragma pack(1)
- #endif
- typedef struct {
- char magic[4];
- uint32_t length;
- float scale;
- uint32_t types;
- } _pack m3dhdr_t;
- typedef struct {
- char magic[4];
- uint32_t length;
- } _pack m3dchunk_t;
- #ifdef _MSC_VER
- #pragma pack(pop)
- #endif
- typedef struct {
- M3D_FLOAT u;
- M3D_FLOAT v;
- } m3dti_t;
- #define m3d_textureindex_t m3dti_t
- typedef struct {
- char *name;
- uint8_t *d;
- uint16_t w;
- uint16_t h;
- uint8_t f;
- } m3dtx_t;
- #define m3d_texturedata_t m3dtx_t
- typedef struct {
- M3D_INDEX vertexid;
- M3D_FLOAT weight;
- } m3dw_t;
- #define m3d_weight_t m3dw_t
- typedef struct {
- M3D_INDEX parent;
- char *name;
- M3D_INDEX pos;
- M3D_INDEX ori;
- M3D_INDEX numweight;
- m3dw_t *weight;
- M3D_FLOAT mat4[16];
- } m3db_t;
- #define m3d_bone_t m3db_t
- typedef struct {
- M3D_INDEX boneid[M3D_NUMBONE];
- M3D_FLOAT weight[M3D_NUMBONE];
- } m3ds_t;
- #define m3d_skin_t m3ds_t
- typedef struct {
- M3D_FLOAT x;
- M3D_FLOAT y;
- M3D_FLOAT z;
- M3D_FLOAT w;
- uint32_t color;
- M3D_INDEX skinid;
- #ifdef M3D_VERTEXTYPE
- uint8_t type;
- #endif
- } m3dv_t;
- #define m3d_vertex_t m3dv_t
- enum {
- m3dpf_color,
- m3dpf_uint8,
- m3dpf_uint16,
- m3dpf_uint32,
- m3dpf_float,
- m3dpf_map
- };
- typedef struct {
- uint8_t format;
- uint8_t id;
- #ifndef M3D_ASCII
- #define M3D_PROPERTYDEF(f,i,n) { (f), (i) }
- #endif
- } m3dpd_t;
- enum {
- m3dp_Kd = 0,
- m3dp_Ka,
- m3dp_Ks,
- m3dp_Ns,
- m3dp_Ke,
- m3dp_Tf,
- m3dp_Km,
- m3dp_d,
- m3dp_il,
- m3dp_Pr = 64,
- m3dp_Pm,
- m3dp_Ps,
- m3dp_Ni,
- m3dp_Nt,
- m3dp_map_Kd = 128,
- m3dp_map_Ka,
- m3dp_map_Ks,
- m3dp_map_Ns,
- m3dp_map_Ke,
- m3dp_map_Tf,
- m3dp_map_Km,
- m3dp_map_D,
- m3dp_map_N,
- m3dp_map_Pr = 192,
- m3dp_map_Pm,
- m3dp_map_Ps,
- m3dp_map_Ni,
- m3dp_map_Nt
- };
- enum {
- m3dp_bump = m3dp_map_Km,
- m3dp_map_il = m3dp_map_N,
- m3dp_refl = m3dp_map_Pm
- };
- typedef struct {
- uint8_t type;
- union {
- uint32_t color;
- uint32_t num;
- float fnum;
- M3D_INDEX textureid;
- } value;
- } m3dp_t;
- #define m3d_property_t m3dp_t
- typedef struct {
- char *name;
- uint8_t numprop;
- m3dp_t *prop;
- } m3dm_t;
- #define m3d_material_t m3dm_t
- typedef struct {
- M3D_INDEX materialid;
- M3D_INDEX vertex[3];
- M3D_INDEX normal[3];
- M3D_INDEX texcoord[3];
- #ifdef M3D_VERTEXMAX
- M3D_INDEX paramid;
- M3D_INDEX vertmax[3];
- #endif
- } m3df_t;
- #define m3d_face_t m3df_t
- typedef struct {
- uint16_t count;
- char *name;
- } m3dvi_t;
- #define m3d_voxelitem_t m3dvi_t
- #define m3d_parameter_t m3dvi_t
- typedef struct {
- char *name;
- uint8_t rotation;
- uint16_t voxshape;
- M3D_INDEX materialid;
- uint32_t color;
- M3D_INDEX skinid;
- uint8_t numitem;
- m3dvi_t *item;
- } m3dvt_t;
- #define m3d_voxeltype_t m3dvt_t
- typedef struct {
- char *name;
- int32_t x, y, z;
- uint32_t w, h, d;
- uint8_t uncertain;
- uint8_t groupid;
- M3D_VOXEL *data;
- } m3dvx_t;
- #define m3d_voxel_t m3dvx_t
- enum {
- m3dc_use = 0,
- m3dc_inc,
- m3dc_mesh,
- m3dc_div,
- m3dc_sub,
- m3dc_len,
- m3dc_dist,
- m3dc_degu,
- m3dc_deg,
- m3dc_rangeu,
- m3dc_range,
- m3dc_paru,
- m3dc_parv,
- m3dc_trim,
- m3dc_hole,
- m3dc_scrv,
- m3dc_sp,
- m3dc_bez1,
- m3dc_bsp1,
- m3dc_bez2,
- m3dc_bsp2,
- m3dc_bezun,
- m3dc_bezu,
- m3dc_bezn,
- m3dc_bez,
- m3dc_nurbsun,
- m3dc_nurbsu,
- m3dc_nurbsn,
- m3dc_nurbs,
- m3dc_conn,
- m3dc_line,
- m3dc_polygon,
- m3dc_circle,
- m3dc_cylinder,
- m3dc_shpere,
- m3dc_torus,
- m3dc_cone,
- m3dc_cube
- };
- enum {
- m3dcp_mi_t = 1,
- m3dcp_hi_t,
- m3dcp_fi_t,
- m3dcp_ti_t,
- m3dcp_vi_t,
- m3dcp_qi_t,
- m3dcp_vc_t,
- m3dcp_i1_t,
- m3dcp_i2_t,
- m3dcp_i4_t,
- m3dcp_va_t
- };
- #define M3D_CMDMAXARG 8
- typedef struct {
- #ifndef M3D_ASCII
- #define M3D_CMDDEF(t,n,p,a,b,c,d,e,f,g,h) { (p), { (a), (b), (c), (d), (e), (f), (g), (h) } }
- #endif
- uint8_t p;
- uint8_t a[M3D_CMDMAXARG];
- } m3dcd_t;
- typedef struct {
- uint16_t type;
- uint32_t *arg;
- } m3dc_t;
- #define m3d_shapecommand_t m3dc_t
- typedef struct {
- char *name;
- M3D_INDEX group;
- uint32_t numcmd;
- m3dc_t *cmd;
- } m3dh_t;
- #define m3d_shape_t m3dh_t
- typedef struct {
- char *name;
- char *lang;
- char *text;
- uint32_t color;
- M3D_INDEX vertexid;
- } m3dl_t;
- #define m3d_label_t m3dl_t
- typedef struct {
- M3D_INDEX boneid;
- M3D_INDEX pos;
- M3D_INDEX ori;
- } m3dtr_t;
- #define m3d_transform_t m3dtr_t
- typedef struct {
- uint32_t msec;
- M3D_INDEX numtransform;
- m3dtr_t *transform;
- } m3dfr_t;
- #define m3d_frame_t m3dfr_t
- typedef struct {
- char *name;
- uint32_t durationmsec;
- M3D_INDEX numframe;
- m3dfr_t *frame;
- } m3da_t;
- #define m3d_action_t m3da_t
- typedef struct {
- char *name;
- uint8_t *data;
- uint32_t length;
- } m3di_t;
- #define m3d_inlinedasset_t m3di_t
- #define M3D_FLG_FREERAW (1<<0)
- #define M3D_FLG_FREESTR (1<<1)
- #define M3D_FLG_MTLLIB (1<<2)
- #define M3D_FLG_GENNORM (1<<3)
- typedef struct {
- m3dhdr_t *raw;
- char flags;
- signed char errcode;
- char vc_s, vi_s, si_s, ci_s, ti_s, bi_s, nb_s, sk_s, fc_s, hi_s, fi_s, vd_s, vp_s;
- char *name;
- char *license;
- char *author;
- char *desc;
- M3D_FLOAT scale;
- M3D_INDEX numcmap;
- uint32_t *cmap;
- M3D_INDEX numtmap;
- m3dti_t *tmap;
- M3D_INDEX numtexture;
- m3dtx_t *texture;
- M3D_INDEX numbone;
- m3db_t *bone;
- M3D_INDEX numvertex;
- m3dv_t *vertex;
- M3D_INDEX numskin;
- m3ds_t *skin;
- M3D_INDEX nummaterial;
- m3dm_t *material;
- #ifdef M3D_VERTEXMAX
- M3D_INDEX numparam;
- m3dvi_t *param;
- #endif
- M3D_INDEX numface;
- m3df_t *face;
- M3D_INDEX numvoxtype;
- m3dvt_t *voxtype;
- M3D_INDEX numvoxel;
- m3dvx_t *voxel;
- M3D_INDEX numshape;
- m3dh_t *shape;
- M3D_INDEX numlabel;
- m3dl_t *label;
- M3D_INDEX numaction;
- m3da_t *action;
- M3D_INDEX numinlined;
- m3di_t *inlined;
- M3D_INDEX numextra;
- m3dchunk_t **extra;
- m3di_t preview;
- } m3d_t;
- #define M3D_EXP_INT8 0
- #define M3D_EXP_INT16 1
- #define M3D_EXP_FLOAT 2
- #define M3D_EXP_DOUBLE 3
- #define M3D_EXP_NOCMAP (1<<0)
- #define M3D_EXP_NOMATERIAL (1<<1)
- #define M3D_EXP_NOFACE (1<<2)
- #define M3D_EXP_NONORMAL (1<<3)
- #define M3D_EXP_NOTXTCRD (1<<4)
- #define M3D_EXP_FLIPTXTCRD (1<<5)
- #define M3D_EXP_NORECALC (1<<6)
- #define M3D_EXP_IDOSUCK (1<<7)
- #define M3D_EXP_NOBONE (1<<8)
- #define M3D_EXP_NOACTION (1<<9)
- #define M3D_EXP_INLINE (1<<10)
- #define M3D_EXP_EXTRA (1<<11)
- #define M3D_EXP_NOZLIB (1<<14)
- #define M3D_EXP_ASCII (1<<15)
- #define M3D_EXP_NOVRTMAX (1<<16)
- #define M3D_SUCCESS 0
- #define M3D_ERR_ALLOC -1
- #define M3D_ERR_BADFILE -2
- #define M3D_ERR_UNIMPL -65
- #define M3D_ERR_UNKPROP -66
- #define M3D_ERR_UNKMESH -67
- #define M3D_ERR_UNKIMG -68
- #define M3D_ERR_UNKFRAME -69
- #define M3D_ERR_UNKCMD -70
- #define M3D_ERR_UNKVOX -71
- #define M3D_ERR_TRUNC -72
- #define M3D_ERR_CMAP -73
- #define M3D_ERR_TMAP -74
- #define M3D_ERR_VRTS -75
- #define M3D_ERR_BONE -76
- #define M3D_ERR_MTRL -77
- #define M3D_ERR_SHPE -78
- #define M3D_ERR_VOXT -79
- #define M3D_ERR_ISFATAL(x) ((x) < 0 && (x) > -65)
- typedef unsigned char *(*m3dread_t)(char *filename, unsigned int *size);
- typedef void (*m3dfree_t)(void *buffer);
- typedef int (*m3dtxsc_t)(const char *name, const void *script, uint32_t len, m3dtx_t *output);
- typedef int (*m3dprsc_t)(const char *name, const void *script, uint32_t len, m3d_t *model);
- #endif
- m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d_t *mtllib);
- unsigned char *m3d_save(m3d_t *model, int quality, int flags, unsigned int *size);
- void m3d_free(m3d_t *model);
- m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t *skeleton);
- m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec);
- char *_m3d_safestr(char *in, int morelines);
- #ifdef M3D_IMPLEMENTATION
- #if !defined(M3D_NOIMPORTER) || defined(M3D_EXPORTER)
- static m3dpd_t m3d_propertytypes[] = {
- M3D_PROPERTYDEF(m3dpf_color, m3dp_Kd, "Kd"),
- M3D_PROPERTYDEF(m3dpf_color, m3dp_Ka, "Ka"),
- M3D_PROPERTYDEF(m3dpf_color, m3dp_Ks, "Ks"),
- M3D_PROPERTYDEF(m3dpf_float, m3dp_Ns, "Ns"),
- M3D_PROPERTYDEF(m3dpf_color, m3dp_Ke, "Ke"),
- M3D_PROPERTYDEF(m3dpf_color, m3dp_Tf, "Tf"),
- M3D_PROPERTYDEF(m3dpf_float, m3dp_Km, "Km"),
- M3D_PROPERTYDEF(m3dpf_float, m3dp_d, "d"),
- M3D_PROPERTYDEF(m3dpf_uint8, m3dp_il, "il"),
- M3D_PROPERTYDEF(m3dpf_float, m3dp_Pr, "Pr"),
- M3D_PROPERTYDEF(m3dpf_float, m3dp_Pm, "Pm"),
- M3D_PROPERTYDEF(m3dpf_float, m3dp_Ps, "Ps"),
- M3D_PROPERTYDEF(m3dpf_float, m3dp_Ni, "Ni"),
- M3D_PROPERTYDEF(m3dpf_float, m3dp_Nt, "Nt"),
- M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Km, "bump"),
- M3D_PROPERTYDEF(m3dpf_map, m3dp_map_N, "map_N"),
- M3D_PROPERTYDEF(m3dpf_map, m3dp_map_Pm, "refl")
- };
- static m3dcd_t m3d_commandtypes[] = {
- M3D_CMDDEF(m3dc_use, "use", 1, m3dcp_mi_t, 0, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_inc, "inc", 3, m3dcp_hi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_mesh, "mesh", 1, m3dcp_fi_t, m3dcp_fi_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vi_t, 0, 0, 0),
- M3D_CMDDEF(m3dc_div, "div", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_sub, "sub", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_len, "len", 1, m3dcp_vc_t, 0, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_dist, "dist", 2, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_degu, "degu", 1, m3dcp_i1_t, 0, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_deg, "deg", 2, m3dcp_i1_t, m3dcp_i1_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_rangeu, "rangeu", 1, m3dcp_ti_t, 0, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_range, "range", 2, m3dcp_ti_t, m3dcp_ti_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_paru, "paru", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_parv, "parv", 2, m3dcp_va_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_trim, "trim", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_hole, "hole", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_scrv, "scrv", 3, m3dcp_va_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_sp, "sp", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_bez1, "bez1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_bsp1, "bsp1", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_bez2, "bez2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_bsp2, "bsp2", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_bezun, "bezun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_bezu, "bezu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_bezn, "bezn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_bez, "bez", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_nurbsun, "nurbsun", 4, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, m3dcp_vi_t, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_nurbsu, "nurbsu", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_ti_t, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_nurbsn, "nurbsn", 3, m3dcp_va_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_nurbs, "nurbs", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_conn, "conn", 6, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, m3dcp_i2_t, m3dcp_ti_t, m3dcp_i2_t, 0, 0),
- M3D_CMDDEF(m3dc_line, "line", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_polygon, "polygon", 2, m3dcp_va_t, m3dcp_vi_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_circle, "circle", 3, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_cylinder,"cylinder",6, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, 0, 0),
- M3D_CMDDEF(m3dc_shpere, "shpere", 2, m3dcp_vi_t, m3dcp_vc_t, 0, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_torus, "torus", 4, m3dcp_vi_t, m3dcp_qi_t, m3dcp_vc_t, m3dcp_vc_t, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_cone, "cone", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0),
- M3D_CMDDEF(m3dc_cube, "cube", 3, m3dcp_vi_t, m3dcp_vi_t, m3dcp_vi_t, 0, 0, 0, 0, 0)
- };
- #endif
- #include <stdlib.h>
- #include <string.h>
- char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
- #define M3D_CHUNKMAGIC(m, a,b,c,d) ((m)[0]==(a) && (m)[1]==(b) && (m)[2]==(c) && (m)[3]==(d))
- #ifndef M3D_NOIMPORTER
- M3D_INDEX _m3d_gettx(m3d_t *model, m3dread_t readfilecb, m3dfree_t freecb, char *fn)
- {
- unsigned int i, len = 0;
- unsigned char *buff = NULL;
- char *fn2;
- if(!fn || !*fn) return M3D_UNDEF;
- for(i = 0; i < model->numtexture; i++)
- if(!strcmp(fn, model->texture[i].name)) return i;
- if(model->inlined) {
- for(i = 0; i < model->numinlined; i++)
- if(!strcmp(fn, model->inlined[i].name)) {
- buff = model->inlined[i].data;
- len = model->inlined[i].length;
- freecb = NULL;
- break;
- }
- }
- if(!buff && readfilecb) {
- i = (unsigned int)strlen(fn);
- if(i < 5 || fn[i - 4] != '.') {
- fn2 = (char*)M3D_MALLOC(i + 5);
- if(!fn2) { model->errcode = M3D_ERR_ALLOC; return M3D_UNDEF; }
- memcpy(fn2, fn, i);
- memcpy(fn2+i, ".png", 5);
- buff = (*readfilecb)(fn2, &len);
- M3D_FREE(fn2);
- }
- if(!buff) {
- buff = (*readfilecb)(fn, &len);
- if(!buff) return M3D_UNDEF;
- }
- }
- i = model->numtexture++;
- model->texture = (m3dtx_t*)M3D_REALLOC(model->texture, model->numtexture * sizeof(m3dtx_t));
- if(!model->texture) {
- if(buff && freecb) (*freecb)(buff);
- model->errcode = M3D_ERR_ALLOC;
- model->numtexture = 0;
- return M3D_UNDEF;
- }
- memset(&model->texture[i], 0, sizeof(m3dtx_t));
- model->texture[i].name = fn;
- if(buff) {
- if(buff[0] == 0x89 && buff[1] == 'P' && buff[2] == 'N' && buff[3] == 'G') {
- } else {
- #ifdef M3D_TX_INTERP
- if((model->errcode = M3D_TX_INTERP(fn, buff, len, &model->texture[i])) != M3D_SUCCESS) {
- M3D_LOG("Unable to generate texture");
- M3D_LOG(fn);
- }
- #else
- M3D_LOG("Unimplemented interpreter");
- M3D_LOG(fn);
- #endif
- }
- if(freecb) (*freecb)(buff);
- }
- if(!model->texture[i].d)
- model->errcode = M3D_ERR_UNKIMG;
- return i;
- }
- void _m3d_getpr(m3d_t *model, _unused m3dread_t readfilecb, _unused m3dfree_t freecb, _unused char *fn)
- {
- #ifdef M3D_PR_INTERP
- unsigned int i, len = 0;
- unsigned char *buff = readfilecb && fn && *fn ? (*readfilecb)(fn, &len) : NULL;
- if(!buff && fn && *fn && model->inlined) {
- for(i = 0; i < model->numinlined; i++)
- if(!strcmp(fn, model->inlined[i].name)) {
- buff = model->inlined[i].data;
- len = model->inlined[i].length;
- freecb = NULL;
- break;
- }
- }
- if(!buff || !len || (model->errcode = M3D_PR_INTERP(fn, buff, len, model)) != M3D_SUCCESS) {
- M3D_LOG("Unable to generate procedural surface");
- M3D_LOG(fn);
- model->errcode = M3D_ERR_UNKIMG;
- }
- if(freecb && buff) (*freecb)(buff);
- #else
- (void)readfilecb;
- (void)freecb;
- (void)fn;
- M3D_LOG("Unimplemented interpreter");
- M3D_LOG(fn);
- model->errcode = M3D_ERR_UNIMPL;
- #endif
- }
- #define M3D_GETSTR(x) do{offs=0;data=_m3d_getidx(data,model->si_s,&offs);x=offs?((char*)model->raw+16+offs):NULL;}while(0)
- _inline static unsigned char *_m3d_getidx(unsigned char *data, char type, M3D_INDEX *idx)
- {
- switch(type) {
- case 1: *idx = data[0] > 253 ? (int8_t)data[0] : data[0]; data++; break;
- case 2: *idx = *((uint16_t*)data) > 65533 ? *((int16_t*)data) : *((uint16_t*)data); data += 2; break;
- case 4: *idx = *((int32_t*)data); data += 4; break;
- }
- return data;
- }
- #ifndef M3D_NOANIMATION
- void _m3d_mul(M3D_FLOAT *r, M3D_FLOAT *a, M3D_FLOAT *b)
- {
- r[ 0] = b[ 0] * a[ 0] + b[ 4] * a[ 1] + b[ 8] * a[ 2] + b[12] * a[ 3];
- r[ 1] = b[ 1] * a[ 0] + b[ 5] * a[ 1] + b[ 9] * a[ 2] + b[13] * a[ 3];
- r[ 2] = b[ 2] * a[ 0] + b[ 6] * a[ 1] + b[10] * a[ 2] + b[14] * a[ 3];
- r[ 3] = b[ 3] * a[ 0] + b[ 7] * a[ 1] + b[11] * a[ 2] + b[15] * a[ 3];
- r[ 4] = b[ 0] * a[ 4] + b[ 4] * a[ 5] + b[ 8] * a[ 6] + b[12] * a[ 7];
- r[ 5] = b[ 1] * a[ 4] + b[ 5] * a[ 5] + b[ 9] * a[ 6] + b[13] * a[ 7];
- r[ 6] = b[ 2] * a[ 4] + b[ 6] * a[ 5] + b[10] * a[ 6] + b[14] * a[ 7];
- r[ 7] = b[ 3] * a[ 4] + b[ 7] * a[ 5] + b[11] * a[ 6] + b[15] * a[ 7];
- r[ 8] = b[ 0] * a[ 8] + b[ 4] * a[ 9] + b[ 8] * a[10] + b[12] * a[11];
- r[ 9] = b[ 1] * a[ 8] + b[ 5] * a[ 9] + b[ 9] * a[10] + b[13] * a[11];
- r[10] = b[ 2] * a[ 8] + b[ 6] * a[ 9] + b[10] * a[10] + b[14] * a[11];
- r[11] = b[ 3] * a[ 8] + b[ 7] * a[ 9] + b[11] * a[10] + b[15] * a[11];
- r[12] = b[ 0] * a[12] + b[ 4] * a[13] + b[ 8] * a[14] + b[12] * a[15];
- r[13] = b[ 1] * a[12] + b[ 5] * a[13] + b[ 9] * a[14] + b[13] * a[15];
- r[14] = b[ 2] * a[12] + b[ 6] * a[13] + b[10] * a[14] + b[14] * a[15];
- r[15] = b[ 3] * a[12] + b[ 7] * a[13] + b[11] * a[14] + b[15] * a[15];
- }
- void _m3d_inv(M3D_FLOAT *m)
- {
- M3D_FLOAT r[16];
- M3D_FLOAT det =
- m[ 0]*m[ 5]*m[10]*m[15] - m[ 0]*m[ 5]*m[11]*m[14] + m[ 0]*m[ 6]*m[11]*m[13] - m[ 0]*m[ 6]*m[ 9]*m[15]
- + m[ 0]*m[ 7]*m[ 9]*m[14] - m[ 0]*m[ 7]*m[10]*m[13] - m[ 1]*m[ 6]*m[11]*m[12] + m[ 1]*m[ 6]*m[ 8]*m[15]
- - m[ 1]*m[ 7]*m[ 8]*m[14] + m[ 1]*m[ 7]*m[10]*m[12] - m[ 1]*m[ 4]*m[10]*m[15] + m[ 1]*m[ 4]*m[11]*m[14]
- + m[ 2]*m[ 7]*m[ 8]*m[13] - m[ 2]*m[ 7]*m[ 9]*m[12] + m[ 2]*m[ 4]*m[ 9]*m[15] - m[ 2]*m[ 4]*m[11]*m[13]
- + m[ 2]*m[ 5]*m[11]*m[12] - m[ 2]*m[ 5]*m[ 8]*m[15] - m[ 3]*m[ 4]*m[ 9]*m[14] + m[ 3]*m[ 4]*m[10]*m[13]
- - m[ 3]*m[ 5]*m[10]*m[12] + m[ 3]*m[ 5]*m[ 8]*m[14] - m[ 3]*m[ 6]*m[ 8]*m[13] + m[ 3]*m[ 6]*m[ 9]*m[12];
- if(det == (M3D_FLOAT)0.0 || det == (M3D_FLOAT)-0.0) det = (M3D_FLOAT)1.0; else det = (M3D_FLOAT)1.0 / det;
- r[ 0] = det *(m[ 5]*(m[10]*m[15] - m[11]*m[14]) + m[ 6]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 7]*(m[ 9]*m[14] - m[10]*m[13]));
- r[ 1] = -det*(m[ 1]*(m[10]*m[15] - m[11]*m[14]) + m[ 2]*(m[11]*m[13] - m[ 9]*m[15]) + m[ 3]*(m[ 9]*m[14] - m[10]*m[13]));
- r[ 2] = det *(m[ 1]*(m[ 6]*m[15] - m[ 7]*m[14]) + m[ 2]*(m[ 7]*m[13] - m[ 5]*m[15]) + m[ 3]*(m[ 5]*m[14] - m[ 6]*m[13]));
- r[ 3] = -det*(m[ 1]*(m[ 6]*m[11] - m[ 7]*m[10]) + m[ 2]*(m[ 7]*m[ 9] - m[ 5]*m[11]) + m[ 3]*(m[ 5]*m[10] - m[ 6]*m[ 9]));
- r[ 4] = -det*(m[ 4]*(m[10]*m[15] - m[11]*m[14]) + m[ 6]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 7]*(m[ 8]*m[14] - m[10]*m[12]));
- r[ 5] = det *(m[ 0]*(m[10]*m[15] - m[11]*m[14]) + m[ 2]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 3]*(m[ 8]*m[14] - m[10]*m[12]));
- r[ 6] = -det*(m[ 0]*(m[ 6]*m[15] - m[ 7]*m[14]) + m[ 2]*(m[ 7]*m[12] - m[ 4]*m[15]) + m[ 3]*(m[ 4]*m[14] - m[ 6]*m[12]));
- r[ 7] = det *(m[ 0]*(m[ 6]*m[11] - m[ 7]*m[10]) + m[ 2]*(m[ 7]*m[ 8] - m[ 4]*m[11]) + m[ 3]*(m[ 4]*m[10] - m[ 6]*m[ 8]));
- r[ 8] = det *(m[ 4]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 5]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 7]*(m[ 8]*m[13] - m[ 9]*m[12]));
- r[ 9] = -det*(m[ 0]*(m[ 9]*m[15] - m[11]*m[13]) + m[ 1]*(m[11]*m[12] - m[ 8]*m[15]) + m[ 3]*(m[ 8]*m[13] - m[ 9]*m[12]));
- r[10] = det *(m[ 0]*(m[ 5]*m[15] - m[ 7]*m[13]) + m[ 1]*(m[ 7]*m[12] - m[ 4]*m[15]) + m[ 3]*(m[ 4]*m[13] - m[ 5]*m[12]));
- r[11] = -det*(m[ 0]*(m[ 5]*m[11] - m[ 7]*m[ 9]) + m[ 1]*(m[ 7]*m[ 8] - m[ 4]*m[11]) + m[ 3]*(m[ 4]*m[ 9] - m[ 5]*m[ 8]));
- r[12] = -det*(m[ 4]*(m[ 9]*m[14] - m[10]*m[13]) + m[ 5]*(m[10]*m[12] - m[ 8]*m[14]) + m[ 6]*(m[ 8]*m[13] - m[ 9]*m[12]));
- r[13] = det *(m[ 0]*(m[ 9]*m[14] - m[10]*m[13]) + m[ 1]*(m[10]*m[12] - m[ 8]*m[14]) + m[ 2]*(m[ 8]*m[13] - m[ 9]*m[12]));
- r[14] = -det*(m[ 0]*(m[ 5]*m[14] - m[ 6]*m[13]) + m[ 1]*(m[ 6]*m[12] - m[ 4]*m[14]) + m[ 2]*(m[ 4]*m[13] - m[ 5]*m[12]));
- r[15] = det *(m[ 0]*(m[ 5]*m[10] - m[ 6]*m[ 9]) + m[ 1]*(m[ 6]*m[ 8] - m[ 4]*m[10]) + m[ 2]*(m[ 4]*m[ 9] - m[ 5]*m[ 8]));
- memcpy(m, &r, sizeof(r));
- }
- void _m3d_mat(M3D_FLOAT *r, m3dv_t *p, m3dv_t *q)
- {
- if(q->x == (M3D_FLOAT)0.0 && q->y == (M3D_FLOAT)0.0 && q->z >=(M3D_FLOAT) 0.7071065 && q->z <= (M3D_FLOAT)0.7071075 &&
- q->w == (M3D_FLOAT)0.0) {
- r[ 1] = r[ 2] = r[ 4] = r[ 6] = r[ 8] = r[ 9] = (M3D_FLOAT)0.0;
- r[ 0] = r[ 5] = r[10] = (M3D_FLOAT)-1.0;
- } else {
- r[ 0] = 1 - 2 * (q->y * q->y + q->z * q->z); if(r[ 0]>-M3D_EPSILON && r[ 0]<M3D_EPSILON) r[ 0]=(M3D_FLOAT)0.0;
- r[ 1] = 2 * (q->x * q->y - q->z * q->w); if(r[ 1]>-M3D_EPSILON && r[ 1]<M3D_EPSILON) r[ 1]=(M3D_FLOAT)0.0;
- r[ 2] = 2 * (q->x * q->z + q->y * q->w); if(r[ 2]>-M3D_EPSILON && r[ 2]<M3D_EPSILON) r[ 2]=(M3D_FLOAT)0.0;
- r[ 4] = 2 * (q->x * q->y + q->z * q->w); if(r[ 4]>-M3D_EPSILON && r[ 4]<M3D_EPSILON) r[ 4]=(M3D_FLOAT)0.0;
- r[ 5] = 1 - 2 * (q->x * q->x + q->z * q->z); if(r[ 5]>-M3D_EPSILON && r[ 5]<M3D_EPSILON) r[ 5]=(M3D_FLOAT)0.0;
- r[ 6] = 2 * (q->y * q->z - q->x * q->w); if(r[ 6]>-M3D_EPSILON && r[ 6]<M3D_EPSILON) r[ 6]=(M3D_FLOAT)0.0;
- r[ 8] = 2 * (q->x * q->z - q->y * q->w); if(r[ 8]>-M3D_EPSILON && r[ 8]<M3D_EPSILON) r[ 8]=(M3D_FLOAT)0.0;
- r[ 9] = 2 * (q->y * q->z + q->x * q->w); if(r[ 9]>-M3D_EPSILON && r[ 9]<M3D_EPSILON) r[ 9]=(M3D_FLOAT)0.0;
- r[10] = 1 - 2 * (q->x * q->x + q->y * q->y); if(r[10]>-M3D_EPSILON && r[10]<M3D_EPSILON) r[10]=(M3D_FLOAT)0.0;
- }
- r[ 3] = p->x; r[ 7] = p->y; r[11] = p->z;
- r[12] = 0; r[13] = 0; r[14] = 0; r[15] = 1;
- }
- #endif
- #if !defined(M3D_NOANIMATION) || !defined(M3D_NONORMALS)
- static M3D_FLOAT _m3d_rsq(M3D_FLOAT x)
- {
- #ifdef M3D_DOUBLE
- return ((M3D_FLOAT)15.0/(M3D_FLOAT)8.0) + ((M3D_FLOAT)-5.0/(M3D_FLOAT)4.0)*x + ((M3D_FLOAT)3.0/(M3D_FLOAT)8.0)*x*x;
- #else
- float x2 = x * 0.5f;
- uint32_t *i = (uint32_t*)&x;
- *i = (0x5f3759df - (*i >> 1));
- return x * (1.5f - (x2 * x * x));
- #endif
- }
- #endif
- m3d_t *m3d_load(unsigned char *data, m3dread_t readfilecb, m3dfree_t freecb, m3d_t *mtllib)
- {
- unsigned char *end, *chunk, *buff, weights[8];
- unsigned int i, j, k, l, n, am, len = 0, reclen, offs;
- #ifndef M3D_NOVOXELS
- int32_t min_x, min_y, min_z, max_x, max_y, max_z, sx, sy, sz, x, y, z;
- M3D_INDEX edge[8], enorm;
- #endif
- char *name, *lang;
- float f;
- m3d_t *model;
- M3D_INDEX mi;
- #ifdef M3D_VERTEXMAX
- M3D_INDEX pi;
- #endif
- M3D_FLOAT w;
- m3dcd_t *cd;
- m3dtx_t *tx;
- m3dh_t *h;
- m3dm_t *m;
- m3da_t *a;
- m3di_t *t;
- #ifndef M3D_NONORMALS
- char neednorm = 0;
- m3dv_t *norm = NULL, *v0, *v1, *v2, va, vb;
- #endif
- #ifndef M3D_NOANIMATION
- M3D_FLOAT r[16];
- #endif
- #if !defined(M3D_NOWEIGHTS) || !defined(M3D_NOANIMATION)
- m3db_t *b;
- #endif
- #ifndef M3D_NOWEIGHTS
- m3ds_t *sk;
- #endif
- if(!data || (!M3D_CHUNKMAGIC(data, '3','D','M','O')
- )) return NULL;
- model = (m3d_t*)M3D_MALLOC(sizeof(m3d_t));
- if(!model) {
- M3D_LOG("Out of memory");
- return NULL;
- }
- memset(model, 0, sizeof(m3d_t));
- if(mtllib) {
- model->nummaterial = mtllib->nummaterial;
- model->material = mtllib->material;
- model->numtexture = mtllib->numtexture;
- model->texture = mtllib->texture;
- model->flags |= M3D_FLG_MTLLIB;
- }
- len = ((m3dhdr_t*)data)->length - 8;
- data += 8;
- if(M3D_CHUNKMAGIC(data, 'P','R','V','W')) {
- model->preview.length = ((m3dchunk_t*)data)->length;
- model->preview.data = data + sizeof(m3dchunk_t);
- data += model->preview.length;
- len -= model->preview.length;
- }
- if(!M3D_CHUNKMAGIC(data, 'H','E','A','D')) {
- buff = (unsigned char *)stbi_zlib_decode_malloc_guesssize_headerflag((const char*)data, len, 4096, (int*)&len, 1);
- if(!buff || !len || !M3D_CHUNKMAGIC(buff, 'H','E','A','D')) {
- if(buff) M3D_FREE(buff);
- M3D_FREE(model);
- return NULL;
- }
- buff = (unsigned char*)M3D_REALLOC(buff, len);
- model->flags |= M3D_FLG_FREERAW;
- data = buff;
- }
- model->raw = (m3dhdr_t*)data;
- end = data + len;
- data += sizeof(m3dhdr_t);
- M3D_LOG((char*)data);
- model->name = (char*)data;
- for(; data < end && *data; data++) {}; data++;
- model->license = (char*)data;
- for(; data < end && *data; data++) {}; data++;
- model->author = (char*)data;
- for(; data < end && *data; data++) {}; data++;
- model->desc = (char*)data;
- chunk = (unsigned char*)model->raw + model->raw->length;
- model->scale = (M3D_FLOAT)model->raw->scale;
- if(model->scale <= (M3D_FLOAT)0.0) model->scale = (M3D_FLOAT)1.0;
- model->vc_s = 1 << ((model->raw->types >> 0) & 3);
- model->vi_s = 1 << ((model->raw->types >> 2) & 3);
- model->si_s = 1 << ((model->raw->types >> 4) & 3);
- model->ci_s = 1 << ((model->raw->types >> 6) & 3);
- model->ti_s = 1 << ((model->raw->types >> 8) & 3);
- model->bi_s = 1 << ((model->raw->types >>10) & 3);
- model->nb_s = 1 << ((model->raw->types >>12) & 3);
- model->sk_s = 1 << ((model->raw->types >>14) & 3);
- model->fc_s = 1 << ((model->raw->types >>16) & 3);
- model->hi_s = 1 << ((model->raw->types >>18) & 3);
- model->fi_s = 1 << ((model->raw->types >>20) & 3);
- model->vd_s = 1 << ((model->raw->types >>22) & 3);
- model->vp_s = 1 << ((model->raw->types >>24) & 3);
- if(model->ci_s == 8) model->ci_s = 0;
- if(model->ti_s == 8) model->ti_s = 0;
- if(model->bi_s == 8) model->bi_s = 0;
- if(model->sk_s == 8) model->sk_s = 0;
- if(model->fc_s == 8) model->fc_s = 0;
- if(model->hi_s == 8) model->hi_s = 0;
- if(model->fi_s == 8) model->fi_s = 0;
- if(sizeof(M3D_FLOAT) == 4 && model->vc_s > 4) {
- M3D_LOG("Double precision coordinates not supported, truncating to float...");
- model->errcode = M3D_ERR_TRUNC;
- }
- if((sizeof(M3D_INDEX) == 2 && (model->vi_s > 2 || model->si_s > 2 || model->ci_s > 2 || model->ti_s > 2 ||
- model->bi_s > 2 || model->sk_s > 2 || model->fc_s > 2 || model->hi_s > 2 || model->fi_s > 2)) ||
- (sizeof(M3D_VOXEL) < (size_t)model->vp_s && model->vp_s != 8)) {
- M3D_LOG("32 bit indices not supported, unable to load model");
- M3D_FREE(model);
- return NULL;
- }
- if(model->vi_s > 4 || model->si_s > 4 || model->vp_s == 4) {
- M3D_LOG("Invalid index size, unable to load model");
- M3D_FREE(model);
- return NULL;
- }
- if(!M3D_CHUNKMAGIC(end - 4, 'O','M','D','3')) {
- M3D_LOG("Missing end chunk");
- M3D_FREE(model);
- return NULL;
- }
- if(model->nb_s > M3D_NUMBONE) {
- M3D_LOG("Model has more bones per vertex than what importer was configured to support");
- model->errcode = M3D_ERR_TRUNC;
- }
- buff = chunk;
- while(buff < end && !M3D_CHUNKMAGIC(buff, 'O','M','D','3')) {
- data = buff;
- len = ((m3dchunk_t*)data)->length;
- buff += len;
- if(len < sizeof(m3dchunk_t) || buff >= end) {
- M3D_LOG("Invalid chunk size");
- break;
- }
- len -= sizeof(m3dchunk_t) + model->si_s;
- if(M3D_CHUNKMAGIC(data, 'A','S','E','T') && len > 0) {
- M3D_LOG("Inlined asset");
- i = model->numinlined++;
- model->inlined = (m3di_t*)M3D_REALLOC(model->inlined, model->numinlined * sizeof(m3di_t));
- if(!model->inlined) {
- memerr: M3D_LOG("Out of memory");
- model->errcode = M3D_ERR_ALLOC;
- return model;
- }
- data += sizeof(m3dchunk_t);
- t = &model->inlined[i];
- M3D_GETSTR(t->name);
- M3D_LOG(t->name);
- t->data = (uint8_t*)data;
- t->length = len;
- }
- }
- while(chunk < end && !M3D_CHUNKMAGIC(chunk, 'O','M','D','3')) {
- data = chunk;
- len = ((m3dchunk_t*)chunk)->length;
- chunk += len;
- if(len < sizeof(m3dchunk_t) || chunk >= end) {
- M3D_LOG("Invalid chunk size");
- break;
- }
- len -= sizeof(m3dchunk_t);
- if(M3D_CHUNKMAGIC(data, 'C','M','A','P')) {
- M3D_LOG("Color map");
- if(model->cmap) { M3D_LOG("More color map chunks, should be unique"); model->errcode = M3D_ERR_CMAP; continue; }
- if(!model->ci_s) { M3D_LOG("Color map chunk, shouldn't be any"); model->errcode = M3D_ERR_CMAP; continue; }
- model->numcmap = len / sizeof(uint32_t);
- model->cmap = (uint32_t*)(data + sizeof(m3dchunk_t));
- } else
- if(M3D_CHUNKMAGIC(data, 'T','M','A','P')) {
- M3D_LOG("Texture map");
- if(model->tmap) { M3D_LOG("More texture map chunks, should be unique"); model->errcode = M3D_ERR_TMAP; continue; }
- if(!model->ti_s) { M3D_LOG("Texture map chunk, shouldn't be any"); model->errcode = M3D_ERR_TMAP; continue; }
- reclen = model->vc_s + model->vc_s;
- model->numtmap = len / reclen;
- model->tmap = (m3dti_t*)M3D_MALLOC(model->numtmap * sizeof(m3dti_t));
- if(!model->tmap) goto memerr;
- for(i = 0, data += sizeof(m3dchunk_t); data < chunk; i++) {
- switch(model->vc_s) {
- case 1:
- model->tmap[i].u = (M3D_FLOAT)((uint8_t)data[0]) / (M3D_FLOAT)255.0;
- model->tmap[i].v = (M3D_FLOAT)((uint8_t)data[1]) / (M3D_FLOAT)255.0;
- break;
- case 2:
- model->tmap[i].u = (M3D_FLOAT)(*((uint16_t*)(data+0))) / (M3D_FLOAT)65535.0;
- model->tmap[i].v = (M3D_FLOAT)(*((uint16_t*)(data+2))) / (M3D_FLOAT)65535.0;
- break;
- case 4:
- model->tmap[i].u = (M3D_FLOAT)(*((float*)(data+0)));
- model->tmap[i].v = (M3D_FLOAT)(*((float*)(data+4)));
- break;
- case 8:
- model->tmap[i].u = (M3D_FLOAT)(*((double*)(data+0)));
- model->tmap[i].v = (M3D_FLOAT)(*((double*)(data+8)));
- break;
- }
- data += reclen;
- }
- } else
- if(M3D_CHUNKMAGIC(data, 'V','R','T','S')) {
- M3D_LOG("Vertex list");
- if(model->vertex) { M3D_LOG("More vertex chunks, should be unique"); model->errcode = M3D_ERR_VRTS; continue; }
- if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP;
- reclen = model->ci_s + model->sk_s + 4 * model->vc_s;
- model->numvertex = len / reclen;
- model->vertex = (m3dv_t*)M3D_MALLOC(model->numvertex * sizeof(m3dv_t));
- if(!model->vertex) goto memerr;
- memset(model->vertex, 0, model->numvertex * sizeof(m3dv_t));
- for(i = 0, data += sizeof(m3dchunk_t); data < chunk && i < model->numvertex; i++) {
- switch(model->vc_s) {
- case 1:
- model->vertex[i].x = (M3D_FLOAT)((int8_t)data[0]) / (M3D_FLOAT)127.0;
- model->vertex[i].y = (M3D_FLOAT)((int8_t)data[1]) / (M3D_FLOAT)127.0;
- model->vertex[i].z = (M3D_FLOAT)((int8_t)data[2]) / (M3D_FLOAT)127.0;
- model->vertex[i].w = (M3D_FLOAT)((int8_t)data[3]) / (M3D_FLOAT)127.0;
- data += 4;
- break;
- case 2:
- model->vertex[i].x = (M3D_FLOAT)(*((int16_t*)(data+0))) / (M3D_FLOAT)32767.0;
- model->vertex[i].y = (M3D_FLOAT)(*((int16_t*)(data+2))) / (M3D_FLOAT)32767.0;
- model->vertex[i].z = (M3D_FLOAT)(*((int16_t*)(data+4))) / (M3D_FLOAT)32767.0;
- model->vertex[i].w = (M3D_FLOAT)(*((int16_t*)(data+6))) / (M3D_FLOAT)32767.0;
- data += 8;
- break;
- case 4:
- model->vertex[i].x = (M3D_FLOAT)(*((float*)(data+0)));
- model->vertex[i].y = (M3D_FLOAT)(*((float*)(data+4)));
- model->vertex[i].z = (M3D_FLOAT)(*((float*)(data+8)));
- model->vertex[i].w = (M3D_FLOAT)(*((float*)(data+12)));
- data += 16;
- break;
- case 8:
- model->vertex[i].x = (M3D_FLOAT)(*((double*)(data+0)));
- model->vertex[i].y = (M3D_FLOAT)(*((double*)(data+8)));
- model->vertex[i].z = (M3D_FLOAT)(*((double*)(data+16)));
- model->vertex[i].w = (M3D_FLOAT)(*((double*)(data+24)));
- data += 32;
- break;
- }
- switch(model->ci_s) {
- case 1: model->vertex[i].color = model->cmap ? model->cmap[data[0]] : 0; data++; break;
- case 2: model->vertex[i].color = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break;
- case 4: model->vertex[i].color = *((uint32_t*)data); data += 4; break;
- }
- model->vertex[i].skinid = M3D_UNDEF;
- data = _m3d_getidx(data, model->sk_s, &model->vertex[i].skinid);
- }
- } else
- if(M3D_CHUNKMAGIC(data, 'B','O','N','E')) {
- M3D_LOG("Skeleton");
- if(model->bone) { M3D_LOG("More bone chunks, should be unique"); model->errcode = M3D_ERR_BONE; continue; }
- if(!model->bi_s) { M3D_LOG("Bone chunk, shouldn't be any"); model->errcode=M3D_ERR_BONE; continue; }
- if(!model->vertex) { M3D_LOG("No vertex chunk before bones"); model->errcode = M3D_ERR_VRTS; break; }
- data += sizeof(m3dchunk_t);
- model->numbone = 0;
- data = _m3d_getidx(data, model->bi_s, &model->numbone);
- if(model->numbone) {
- model->bone = (m3db_t*)M3D_MALLOC(model->numbone * sizeof(m3db_t));
- if(!model->bone) goto memerr;
- }
- model->numskin = 0;
- data = _m3d_getidx(data, model->sk_s, &model->numskin);
- for(i = 0; data < chunk && i < model->numbone; i++) {
- data = _m3d_getidx(data, model->bi_s, &model->bone[i].parent);
- M3D_GETSTR(model->bone[i].name);
- data = _m3d_getidx(data, model->vi_s, &model->bone[i].pos);
- data = _m3d_getidx(data, model->vi_s, &model->bone[i].ori);
- model->bone[i].numweight = 0;
- model->bone[i].weight = NULL;
- }
- if(i != model->numbone) { M3D_LOG("Truncated bone chunk"); model->numbone = i; model->numskin = 0; model->errcode = M3D_ERR_BONE; }
- if(model->numskin) {
- model->skin = (m3ds_t*)M3D_MALLOC(model->numskin * sizeof(m3ds_t));
- if(!model->skin) goto memerr;
- for(i = 0; data < chunk && i < model->numskin; i++) {
- for(j = 0; j < M3D_NUMBONE; j++) {
- model->skin[i].boneid[j] = M3D_UNDEF;
- model->skin[i].weight[j] = (M3D_FLOAT)0.0;
- }
- memset(&weights, 0, sizeof(weights));
- if(model->nb_s == 1) weights[0] = 255;
- else {
- memcpy(&weights, data, model->nb_s);
- data += model->nb_s;
- }
- for(j = 0, w = (M3D_FLOAT)0.0; j < (unsigned int)model->nb_s; j++) {
- if(weights[j]) {
- if(j >= M3D_NUMBONE)
- data += model->bi_s;
- else {
- model->skin[i].weight[j] = (M3D_FLOAT)(weights[j]) / (M3D_FLOAT)255.0;
- w += model->skin[i].weight[j];
- data = _m3d_getidx(data, model->bi_s, &model->skin[i].boneid[j]);
- }
- }
- }
- if(w != (M3D_FLOAT)1.0 && w != (M3D_FLOAT)0.0) {
- for(j = 0; j < M3D_NUMBONE; j++)
- model->skin[i].weight[j] /= w;
- }
- }
- if(i != model->numskin) { M3D_LOG("Truncated skin in bone chunk"); model->numskin = i; model->errcode = M3D_ERR_BONE; }
- }
- } else
- if(M3D_CHUNKMAGIC(data, 'M','T','R','L')) {
- data += sizeof(m3dchunk_t);
- M3D_GETSTR(name);
- M3D_LOG("Material");
- M3D_LOG(name);
- if(model->ci_s < 4 && !model->numcmap) model->errcode = M3D_ERR_CMAP;
- for(i = 0; i < model->nummaterial; i++)
- if(!strcmp(name, model->material[i].name)) {
- model->errcode = M3D_ERR_MTRL;
- M3D_LOG("Multiple definitions for material");
- M3D_LOG(name);
- name = NULL;
- break;
- }
- if(name) {
- i = model->nummaterial++;
- if(model->flags & M3D_FLG_MTLLIB) {
- m = model->material;
- model->material = (m3dm_t*)M3D_MALLOC(model->nummaterial * sizeof(m3dm_t));
- if(!model->material) goto memerr;
- memcpy(model->material, m, (model->nummaterial - 1) * sizeof(m3dm_t));
- if(model->texture) {
- tx = model->texture;
- model->texture = (m3dtx_t*)M3D_MALLOC(model->numtexture * sizeof(m3dtx_t));
- if(!model->texture) goto memerr;
- memcpy(model->texture, tx, model->numtexture * sizeof(m3dm_t));
- }
- model->flags &= ~M3D_FLG_MTLLIB;
- } else {
- model->material = (m3dm_t*)M3D_REALLOC(model->material, model->nummaterial * sizeof(m3dm_t));
- if(!model->material) goto memerr;
- }
- m = &model->material[i];
- m->numprop = 0;
- m->name = name;
- m->prop = (m3dp_t*)M3D_MALLOC((len / 2) * sizeof(m3dp_t));
- if(!m->prop) goto memerr;
- while(data < chunk) {
- i = m->numprop++;
- m->prop[i].type = *data++;
- m->prop[i].value.num = 0;
- if(m->prop[i].type >= 128)
- k = m3dpf_map;
- else {
- for(k = 256, j = 0; j < sizeof(m3d_propertytypes)/sizeof(m3d_propertytypes[0]); j++)
- if(m->prop[i].type == m3d_propertytypes[j].id) { k = m3d_propertytypes[j].format; break; }
- }
- switch(k) {
- case m3dpf_color:
- switch(model->ci_s) {
- case 1: m->prop[i].value.color = model->cmap ? model->cmap[data[0]] : 0; data++; break;
- case 2: m->prop[i].value.color = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break;
- case 4: m->prop[i].value.color = *((uint32_t*)data); data += 4; break;
- }
- break;
- case m3dpf_uint8: m->prop[i].value.num = *data++; break;
- case m3dpf_uint16:m->prop[i].value.num = *((uint16_t*)data); data += 2; break;
- case m3dpf_uint32:m->prop[i].value.num = *((uint32_t*)data); data += 4; break;
- case m3dpf_float: m->prop[i].value.fnum = *((float*)data); data += 4; break;
- case m3dpf_map:
- M3D_GETSTR(name);
- m->prop[i].value.textureid = _m3d_gettx(model, readfilecb, freecb, name);
- if(model->errcode == M3D_ERR_ALLOC) goto memerr;
- if(m->prop[i].value.textureid == M3D_UNDEF) {
- M3D_LOG("Texture not found");
- M3D_LOG(m->name);
- m->numprop--;
- }
- break;
- default:
- M3D_LOG("Unknown material property in");
- M3D_LOG(m->name);
- model->errcode = M3D_ERR_UNKPROP;
- data = chunk;
- break;
- }
- }
- m->prop = (m3dp_t*)M3D_REALLOC(m->prop, m->numprop * sizeof(m3dp_t));
- if(!m->prop) goto memerr;
- }
- } else
- if(M3D_CHUNKMAGIC(data, 'P','R','O','C')) {
- M3D_GETSTR(name);
- M3D_LOG("Procedural surface");
- M3D_LOG(name);
- _m3d_getpr(model, readfilecb, freecb, name);
- } else
- if(M3D_CHUNKMAGIC(data, 'M','E','S','H')) {
- M3D_LOG("Mesh data");
- if(!model->vertex) { M3D_LOG("No vertex chunk before mesh"); model->errcode = M3D_ERR_VRTS; }
- data += sizeof(m3dchunk_t);
- mi = M3D_UNDEF;
- #ifdef M3D_VERTEXMAX
- pi = M3D_UNDEF;
- #endif
- am = model->numface;
- while(data < chunk) {
- k = *data++;
- n = k >> 4;
- k &= 15;
- if(!n) {
- if(!k) {
- mi = M3D_UNDEF;
- M3D_GETSTR(name);
- if(name) {
- for(j = 0; j < model->nummaterial; j++)
- if(!strcmp(name, model->material[j].name)) {
- mi = (M3D_INDEX)j;
- break;
- }
- if(mi == M3D_UNDEF) model->errcode = M3D_ERR_MTRL;
- }
- } else {
- M3D_GETSTR(name);
- #ifdef M3D_VERTEXMAX
- pi = M3D_UNDEF;
- if(name) {
- for(j = 0; j < model->numparam; j++)
- if(!strcmp(name, model->param[j].name)) {
- pi = (M3D_INDEX)j;
- break;
- }
- if(pi == M3D_UNDEF) {
- pi = model->numparam++;
- model->param = (m3dvi_t*)M3D_REALLOC(model->param, model->numparam * sizeof(m3dvi_t));
- if(!model->param) goto memerr;
- model->param[pi].name = name;
- model->param[pi].count = 0;
- }
- }
- #endif
- }
- continue;
- }
- if(n != 3) { M3D_LOG("Only triangle mesh supported for now"); model->errcode = M3D_ERR_UNKMESH; return model; }
- i = model->numface++;
- if(model->numface > am) {
- am = model->numface + 4095;
- model->face = (m3df_t*)M3D_REALLOC(model->face, am * sizeof(m3df_t));
- if(!model->face) goto memerr;
- }
- memset(&model->face[i], 255, sizeof(m3df_t));
- model->face[i].materialid = mi;
- #ifdef M3D_VERTEXMAX
- model->face[i].paramid = pi;
- #endif
- for(j = 0; data < chunk && j < n; j++) {
- data = _m3d_getidx(data, model->vi_s, &model->face[i].vertex[j]);
- if(k & 1)
- data = _m3d_getidx(data, model->ti_s, &model->face[i].texcoord[j]);
- if(k & 2)
- data = _m3d_getidx(data, model->vi_s, &model->face[i].normal[j]);
- #ifndef M3D_NONORMALS
- if(model->face[i].normal[j] == M3D_UNDEF) neednorm = 1;
- #endif
- if(k & 4)
- #ifdef M3D_VERTEXMAX
- data = _m3d_getidx(data, model->vi_s, &model->face[i].vertmax[j]);
- #else
- data += model->vi_s;
- #endif
- }
- if(j != n) { M3D_LOG("Invalid mesh"); model->numface = 0; model->errcode = M3D_ERR_UNKMESH; return model; }
- }
- model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t));
- } else
- if(M3D_CHUNKMAGIC(data, 'V','O','X','T')) {
- M3D_LOG("Voxel types list");
- if(model->voxtype) { M3D_LOG("More voxel type chunks, should be unique"); model->errcode = M3D_ERR_VOXT; continue; }
- if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP;
- reclen = model->ci_s + model->si_s + 3 + model->sk_s;
- k = len / reclen;
- model->voxtype = (m3dvt_t*)M3D_MALLOC(k * sizeof(m3dvt_t));
- if(!model->voxtype) goto memerr;
- memset(model->voxtype, 0, k * sizeof(m3dvt_t));
- model->numvoxtype = 0;
- for(i = 0, data += sizeof(m3dchunk_t); data < chunk && i < k; i++) {
- switch(model->ci_s) {
- case 1: model->voxtype[i].color = model->cmap ? model->cmap[data[0]] : 0; data++; break;
- case 2: model->voxtype[i].color = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break;
- case 4: model->voxtype[i].color = *((uint32_t*)data); data += 4; break;
- }
- M3D_GETSTR(name);
- model->voxtype[i].materialid = M3D_UNDEF;
- if(name) {
- model->voxtype[i].name = name;
- }
- j = *data++;
- model->voxtype[i].rotation = j & 0xBF;
- model->voxtype[i].voxshape = ((j & 0x40) << 2) | *data++;
- model->voxtype[i].numitem = *data++;
- model->voxtype[i].skinid = M3D_UNDEF;
- data = _m3d_getidx(data, model->sk_s, &model->voxtype[i].skinid);
- if(model->voxtype[i].numitem) {
- model->voxtype[i].item = (m3dvi_t*)M3D_MALLOC(model->voxtype[i].numitem * sizeof(m3dvi_t));
- if(!model->voxtype[i].item) goto memerr;
- memset(model->voxtype[i].item, 0, model->voxtype[i].numitem * sizeof(m3dvi_t));
- for(j = 0; j < model->voxtype[i].numitem; j++) {
- model->voxtype[i].item[j].count = *data++;
- model->voxtype[i].item[j].count |= (*data++) << 8;
- M3D_GETSTR(model->voxtype[i].item[j].name);
- }
- }
- }
- model->numvoxtype = i;
- if(k != model->numvoxtype) {
- model->voxtype = (m3dvt_t*)M3D_REALLOC(model->voxtype, model->numvoxtype * sizeof(m3dvt_t));
- if(!model->voxtype) goto memerr;
- }
- } else
- if(M3D_CHUNKMAGIC(data, 'V','O','X','D')) {
- data += sizeof(m3dchunk_t);
- M3D_GETSTR(name);
- M3D_LOG("Voxel Data Layer");
- M3D_LOG(name);
- if(model->vd_s > 4 || model->vp_s > 2) { M3D_LOG("No voxel index size"); model->errcode = M3D_ERR_UNKVOX; continue; }
- if(!model->voxtype) { M3D_LOG("No voxel type chunk before voxel data"); model->errcode = M3D_ERR_VOXT; }
- i = model->numvoxel++;
- model->voxel = (m3dvx_t*)M3D_REALLOC(model->voxel, model->numvoxel * sizeof(m3dvx_t));
- if(!model->voxel) goto memerr;
- memset(&model->voxel[i], 0, sizeof(m3dvx_t));
- model->voxel[i].name = name;
- switch(model->vd_s) {
- case 1:
- model->voxel[i].x = (int32_t)((int8_t)data[0]);
- model->voxel[i].y = (int32_t)((int8_t)data[1]);
- model->voxel[i].z = (int32_t)((int8_t)data[2]);
- model->voxel[i].w = (uint32_t)(data[3]);
- model->voxel[i].h = (uint32_t)(data[4]);
- model->voxel[i].d = (uint32_t)(data[5]);
- data += 6;
- break;
- case 2:
- model->voxel[i].x = (int32_t)(*((int16_t*)(data+0)));
- model->voxel[i].y = (int32_t)(*((int16_t*)(data+2)));
- model->voxel[i].z = (int32_t)(*((int16_t*)(data+4)));
- model->voxel[i].w = (uint32_t)(*((uint16_t*)(data+6)));
- model->voxel[i].h = (uint32_t)(*((uint16_t*)(data+8)));
- model->voxel[i].d = (uint32_t)(*((uint16_t*)(data+10)));
- data += 12;
- break;
- case 4:
- model->voxel[i].x = *((int32_t*)(data+0));
- model->voxel[i].y = *((int32_t*)(data+4));
- model->voxel[i].z = *((int32_t*)(data+8));
- model->voxel[i].w = *((uint32_t*)(data+12));
- model->voxel[i].h = *((uint32_t*)(data+16));
- model->voxel[i].d = *((uint32_t*)(data+20));
- data += 24;
- break;
- }
- model->voxel[i].uncertain = *data++;
- model->voxel[i].groupid = *data++;
- k = model->voxel[i].w * model->voxel[i].h * model->voxel[i].d;
- model->voxel[i].data = (M3D_VOXEL*)M3D_MALLOC(k * sizeof(M3D_VOXEL));
- if(!model->voxel[i].data) goto memerr;
- memset(model->voxel[i].data, 0xff, k * sizeof(M3D_VOXEL));
- for(j = 0; data < chunk && j < k;) {
- l = ((*data++) & 0x7F) + 1;
- if(data[-1] & 0x80) {
- data = _m3d_getidx(data, model->vp_s, &mi);
- while(l-- && j < k) model->voxel[i].data[j++] = (M3D_VOXEL)mi;
- } else
- while(l-- && j < k) {
- data = _m3d_getidx(data, model->vp_s, &mi);
- model->voxel[i].data[j++] = (M3D_VOXEL)mi;
- }
- }
- } else
- if(M3D_CHUNKMAGIC(data, 'S','H','P','E')) {
- data += sizeof(m3dchunk_t);
- M3D_GETSTR(name);
- M3D_LOG("Mathematical Shape");
- M3D_LOG(name);
- i = model->numshape++;
- model->shape = (m3dh_t*)M3D_REALLOC(model->shape, model->numshape * sizeof(m3dh_t));
- if(!model->shape) goto memerr;
- h = &model->shape[i];
- h->numcmd = 0;
- h->cmd = NULL;
- h->name = name;
- h->group = M3D_UNDEF;
- data = _m3d_getidx(data, model->bi_s, &h->group);
- if(h->group != M3D_UNDEF && h->group >= model->numbone) {
- M3D_LOG("Unknown bone id as shape group in shape");
- M3D_LOG(name);
- h->group = M3D_UNDEF;
- model->errcode = M3D_ERR_SHPE;
- }
- while(data < chunk) {
- i = h->numcmd++;
- h->cmd = (m3dc_t*)M3D_REALLOC(h->cmd, h->numcmd * sizeof(m3dc_t));
- if(!h->cmd) goto memerr;
- h->cmd[i].type = *data++;
- if(h->cmd[i].type & 0x80) {
- h->cmd[i].type &= 0x7F;
- h->cmd[i].type |= (*data++ << 7);
- }
- if(h->cmd[i].type >= (unsigned int)(sizeof(m3d_commandtypes)/sizeof(m3d_commandtypes[0]))) {
- M3D_LOG("Unknown shape command in");
- M3D_LOG(h->name);
- model->errcode = M3D_ERR_UNKCMD;
- break;
- }
- cd = &m3d_commandtypes[h->cmd[i].type];
- h->cmd[i].arg = (uint32_t*)M3D_MALLOC(cd->p * sizeof(uint32_t));
- if(!h->cmd[i].arg) goto memerr;
- memset(h->cmd[i].arg, 0, cd->p * sizeof(uint32_t));
- for(k = n = 0, l = cd->p; k < l; k++)
- switch(cd->a[((k - n) % (cd->p - n)) + n]) {
- case m3dcp_mi_t:
- h->cmd[i].arg[k] = M3D_NOTDEFINED;
- M3D_GETSTR(name);
- if(name) {
- for(n = 0; n < model->nummaterial; n++)
- if(!strcmp(name, model->material[n].name)) {
- h->cmd[i].arg[k] = n;
- break;
- }
- if(h->cmd[i].arg[k] == M3D_NOTDEFINED) model->errcode = M3D_ERR_MTRL;
- }
- break;
- case m3dcp_vc_t:
- f = 0.0f;
- switch(model->vc_s) {
- case 1: f = (float)((int8_t)data[0]) / 127; break;
- case 2: f = (float)(*((int16_t*)(data+0))) / 32767; break;
- case 4: f = (float)(*((float*)(data+0))); break;
- case 8: f = (float)(*((double*)(data+0))); break;
- }
- memcpy(&h->cmd[i].arg[k], &f, 4);
- data += model->vc_s;
- break;
- case m3dcp_hi_t: data = _m3d_getidx(data, model->hi_s, &h->cmd[i].arg[k]); break;
- case m3dcp_fi_t: data = _m3d_getidx(data, model->fi_s, &h->cmd[i].arg[k]); break;
- case m3dcp_ti_t: data = _m3d_getidx(data, model->ti_s, &h->cmd[i].arg[k]); break;
- case m3dcp_qi_t:
- case m3dcp_vi_t: data = _m3d_getidx(data, model->vi_s, &h->cmd[i].arg[k]); break;
- case m3dcp_i1_t: data = _m3d_getidx(data, 1, &h->cmd[i].arg[k]); break;
- case m3dcp_i2_t: data = _m3d_getidx(data, 2, &h->cmd[i].arg[k]); break;
- case m3dcp_i4_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]); break;
- case m3dcp_va_t: data = _m3d_getidx(data, 4, &h->cmd[i].arg[k]);
- n = k + 1; l += (h->cmd[i].arg[k] - 1) * (cd->p - k - 1);
- h->cmd[i].arg = (uint32_t*)M3D_REALLOC(h->cmd[i].arg, l * sizeof(uint32_t));
- if(!h->cmd[i].arg) goto memerr;
- memset(&h->cmd[i].arg[k + 1], 0, (l - k - 1) * sizeof(uint32_t));
- break;
- }
- }
- } else
- if(M3D_CHUNKMAGIC(data, 'L','B','L','S')) {
- data += sizeof(m3dchunk_t);
- M3D_GETSTR(name);
- M3D_GETSTR(lang);
- M3D_LOG("Label list");
- if(name) { M3D_LOG(name); }
- if(lang) { M3D_LOG(lang); }
- if(model->ci_s && model->ci_s < 4 && !model->cmap) model->errcode = M3D_ERR_CMAP;
- k = 0;
- switch(model->ci_s) {
- case 1: k = model->cmap ? model->cmap[data[0]] : 0; data++; break;
- case 2: k = model->cmap ? model->cmap[*((uint16_t*)data)] : 0; data += 2; break;
- case 4: k = *((uint32_t*)data); data += 4; break;
- }
- reclen = model->vi_s + model->si_s;
- i = model->numlabel; model->numlabel += len / reclen;
- model->label = (m3dl_t*)M3D_REALLOC(model->label, model->numlabel * sizeof(m3dl_t));
- if(!model->label) goto memerr;
- memset(&model->label[i], 0, (model->numlabel - i) * sizeof(m3dl_t));
- for(; data < chunk && i < model->numlabel; i++) {
- model->label[i].name = name;
- model->label[i].lang = lang;
- model->label[i].color = k;
- data = _m3d_getidx(data, model->vi_s, &model->label[i].vertexid);
- M3D_GETSTR(model->label[i].text);
- }
- } else
- if(M3D_CHUNKMAGIC(data, 'A','C','T','N')) {
- M3D_LOG("Action");
- i = model->numaction++;
- model->action = (m3da_t*)M3D_REALLOC(model->action, model->numaction * sizeof(m3da_t));
- if(!model->action) goto memerr;
- a = &model->action[i];
- data += sizeof(m3dchunk_t);
- M3D_GETSTR(a->name);
- M3D_LOG(a->name);
- a->numframe = *((uint16_t*)data); data += 2;
- if(a->numframe < 1) {
- model->numaction--;
- } else {
- a->durationmsec = *((uint32_t*)data); data += 4;
- a->frame = (m3dfr_t*)M3D_MALLOC(a->numframe * sizeof(m3dfr_t));
- if(!a->frame) goto memerr;
- for(i = 0; data < chunk && i < a->numframe; i++) {
- a->frame[i].msec = *((uint32_t*)data); data += 4;
- a->frame[i].numtransform = 0; a->frame[i].transform = NULL;
- data = _m3d_getidx(data, model->fc_s, &a->frame[i].numtransform);
- if(a->frame[i].numtransform > 0) {
- a->frame[i].transform = (m3dtr_t*)M3D_MALLOC(a->frame[i].numtransform * sizeof(m3dtr_t));
- for(j = 0; j < a->frame[i].numtransform; j++) {
- data = _m3d_getidx(data, model->bi_s, &a->frame[i].transform[j].boneid);
- data = _m3d_getidx(data, model->vi_s, &a->frame[i].transform[j].pos);
- data = _m3d_getidx(data, model->vi_s, &a->frame[i].transform[j].ori);
- }
- }
- }
- }
- } else {
- i = model->numextra++;
- model->extra = (m3dchunk_t**)M3D_REALLOC(model->extra, model->numextra * sizeof(m3dchunk_t*));
- if(!model->extra) goto memerr;
- model->extra[i] = (m3dchunk_t*)data;
- }
- }
- if(model) {
- M3D_LOG("Post-process");
- #ifndef M3D_NOVOXELS
- if(model->numvoxel && model->voxel) {
- M3D_LOG("Converting voxels into vertices and mesh");
- enorm = model->numvertex; model->numvertex += 6;
- model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t));
- if(!model->vertex) goto memerr;
- memset(&model->vertex[enorm], 0, 6 * sizeof(m3dv_t));
- for(l = 0; l < 6; l++)
- model->vertex[enorm+l].skinid = M3D_UNDEF;
- model->vertex[enorm+0].y = (M3D_FLOAT)-1.0;
- model->vertex[enorm+1].z = (M3D_FLOAT)-1.0;
- model->vertex[enorm+2].x = (M3D_FLOAT)-1.0;
- model->vertex[enorm+3].y = (M3D_FLOAT)1.0;
- model->vertex[enorm+4].z = (M3D_FLOAT)1.0;
- model->vertex[enorm+5].x = (M3D_FLOAT)1.0;
- min_x = min_y = min_z = 2147483647L;
- max_x = max_y = max_z = -2147483647L;
- for(i = 0; i < model->numvoxel; i++) {
- if(model->voxel[i].x + (int32_t)model->voxel[i].w > max_x) max_x = model->voxel[i].x + (int32_t)model->voxel[i].w;
- if(model->voxel[i].x < min_x) min_x = model->voxel[i].x;
- if(model->voxel[i].y + (int32_t)model->voxel[i].h > max_y) max_y = model->voxel[i].y + (int32_t)model->voxel[i].h;
- if(model->voxel[i].y < min_y) min_y = model->voxel[i].y;
- if(model->voxel[i].z + (int32_t)model->voxel[i].d > max_z) max_z = model->voxel[i].z + (int32_t)model->voxel[i].d;
- if(model->voxel[i].z < min_z) min_z = model->voxel[i].z;
- }
- i = (-min_x > max_x ? -min_x : max_x);
- j = (-min_y > max_y ? -min_y : max_y);
- k = (-min_z > max_z ? -min_z : max_z);
- if(j > i) i = j;
- if(k > i) i = k;
- if(i <= 1) i = 1;
- w = (M3D_FLOAT)1.0 / (M3D_FLOAT)i;
- if(i >= 254) model->vc_s = 2;
- if(i >= 65534) model->vc_s = 4;
- for(i = 0; i < model->numvoxel; i++) {
- sx = model->voxel[i].w; sz = model->voxel[i].d; sy = model->voxel[i].h;
- for(y = 0, j = 0; y < sy; y++)
- for(z = 0; z < sz; z++)
- for(x = 0; x < sx; x++, j++)
- if(model->voxel[i].data[j] < model->numvoxtype) {
- k = 0;
- k = n = am = 0;
- if(!y || model->voxel[i].data[j - sx*sz] >= model->numvoxtype) { n++; am |= 1; k |= 1|2|4|8; }
- if(!z || model->voxel[i].data[j - sx] >= model->numvoxtype) { n++; am |= 2; k |= 1|2|16|32; }
- if(!x || model->voxel[i].data[j - 1] >= model->numvoxtype) { n++; am |= 4; k |= 1|4|16|64; }
- if(y == sy-1 || model->voxel[i].data[j + sx*sz] >= model->numvoxtype) { n++; am |= 8; k |= 16|32|64|128; }
- if(z == sz-1 || model->voxel[i].data[j + sx] >= model->numvoxtype) { n++; am |= 16; k |= 4|8|64|128; }
- if(x == sx-1 || model->voxel[i].data[j + 1] >= model->numvoxtype) { n++; am |= 32; k |= 2|8|32|128; }
- if(k) {
- memset(edge, 255, sizeof(edge));
- for(l = 0, len = 1, reclen = model->numvertex; l < 8; l++, len <<= 1)
- if(k & len) edge[l] = model->numvertex++;
- model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t));
- if(!model->vertex) goto memerr;
- memset(&model->vertex[reclen], 0, (model->numvertex-reclen) * sizeof(m3dv_t));
- for(l = reclen; l < model->numvertex; l++) {
- model->vertex[l].skinid = model->voxtype[model->voxel[i].data[j]].skinid;
- model->vertex[l].color = model->voxtype[model->voxel[i].data[j]].color;
- }
- l = reclen;
- if(k & 1) {
- model->vertex[l].x = (model->voxel[i].x + x) * w;
- model->vertex[l].y = (model->voxel[i].y + y) * w;
- model->vertex[l].z = (model->voxel[i].z + z) * w;
- l++;
- }
- if(k & 2) {
- model->vertex[l].x = (model->voxel[i].x + x + 1) * w;
- model->vertex[l].y = (model->voxel[i].y + y) * w;
- model->vertex[l].z = (model->voxel[i].z + z) * w;
- l++;
- }
- if(k & 4) {
- model->vertex[l].x = (model->voxel[i].x + x) * w;
- model->vertex[l].y = (model->voxel[i].y + y) * w;
- model->vertex[l].z = (model->voxel[i].z + z + 1) * w;
- l++;
- }
- if(k & 8) {
- model->vertex[l].x = (model->voxel[i].x + x + 1) * w;
- model->vertex[l].y = (model->voxel[i].y + y) * w;
- model->vertex[l].z = (model->voxel[i].z + z + 1) * w;
- l++;
- }
- if(k & 16) {
- model->vertex[l].x = (model->voxel[i].x + x) * w;
- model->vertex[l].y = (model->voxel[i].y + y + 1) * w;
- model->vertex[l].z = (model->voxel[i].z + z) * w;
- l++;
- }
- if(k & 32) {
- model->vertex[l].x = (model->voxel[i].x + x + 1) * w;
- model->vertex[l].y = (model->voxel[i].y + y + 1) * w;
- model->vertex[l].z = (model->voxel[i].z + z) * w;
- l++;
- }
- if(k & 64) {
- model->vertex[l].x = (model->voxel[i].x + x) * w;
- model->vertex[l].y = (model->voxel[i].y + y + 1) * w;
- model->vertex[l].z = (model->voxel[i].z + z + 1) * w;
- l++;
- }
- if(k & 128) {
- model->vertex[l].x = (model->voxel[i].x + x + 1) * w;
- model->vertex[l].y = (model->voxel[i].y + y + 1) * w;
- model->vertex[l].z = (model->voxel[i].z + z + 1) * w;
- l++;
- }
- n <<= 1;
- l = model->numface; model->numface += n;
- model->face = (m3df_t*)M3D_REALLOC(model->face, model->numface * sizeof(m3df_t));
- if(!model->face) goto memerr;
- memset(&model->face[l], 255, n * sizeof(m3df_t));
- for(reclen = l; reclen < model->numface; reclen++)
- model->face[reclen].materialid = model->voxtype[model->voxel[i].data[j]].materialid;
- if(am & 1) {
- model->face[l].vertex[0] = edge[0]; model->face[l].vertex[1] = edge[1]; model->face[l].vertex[2] = edge[2];
- model->face[l+1].vertex[0] = edge[2]; model->face[l+1].vertex[1] = edge[1]; model->face[l+1].vertex[2] = edge[3];
- model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] =
- model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm;
- l += 2;
- }
- if(am & 2) {
- model->face[l].vertex[0] = edge[0]; model->face[l].vertex[1] = edge[4]; model->face[l].vertex[2] = edge[1];
- model->face[l+1].vertex[0] = edge[1]; model->face[l+1].vertex[1] = edge[4]; model->face[l+1].vertex[2] = edge[5];
- model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] =
- model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+1;
- l += 2;
- }
- if(am & 4) {
- model->face[l].vertex[0] = edge[0]; model->face[l].vertex[1] = edge[2]; model->face[l].vertex[2] = edge[4];
- model->face[l+1].vertex[0] = edge[2]; model->face[l+1].vertex[1] = edge[6]; model->face[l+1].vertex[2] = edge[4];
- model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] =
- model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+2;
- l += 2;
- }
- if(am & 8) {
- model->face[l].vertex[0] = edge[4]; model->face[l].vertex[1] = edge[6]; model->face[l].vertex[2] = edge[5];
- model->face[l+1].vertex[0] = edge[5]; model->face[l+1].vertex[1] = edge[6]; model->face[l+1].vertex[2] = edge[7];
- model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] =
- model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+3;
- l += 2;
- }
- if(am & 16) {
- model->face[l].vertex[0] = edge[2]; model->face[l].vertex[1] = edge[7]; model->face[l].vertex[2] = edge[6];
- model->face[l+1].vertex[0] = edge[7]; model->face[l+1].vertex[1] = edge[2]; model->face[l+1].vertex[2] = edge[3];
- model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] =
- model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+4;
- l += 2;
- }
- if(am & 32) {
- model->face[l].vertex[0] = edge[1]; model->face[l].vertex[1] = edge[5]; model->face[l].vertex[2] = edge[7];
- model->face[l+1].vertex[0] = edge[1]; model->face[l+1].vertex[1] = edge[7]; model->face[l+1].vertex[2] = edge[3];
- model->face[l].normal[0] = model->face[l].normal[1] = model->face[l].normal[2] =
- model->face[l+1].normal[0] = model->face[l+1].normal[1] = model->face[l+1].normal[2] = enorm+5;
- l += 2;
- }
- }
- }
- }
- }
- #endif
- #ifndef M3D_NONORMALS
- if(model->numface && model->face && neednorm) {
- norm = (m3dv_t*)M3D_MALLOC(model->numface * sizeof(m3dv_t));
- if(!norm) goto memerr;
- for(i = 0, n = model->numvertex; i < model->numface; i++)
- if(model->face[i].normal[0] == M3D_UNDEF) {
- v0 = &model->vertex[model->face[i].vertex[0]];
- v1 = &model->vertex[model->face[i].vertex[1]];
- v2 = &model->vertex[model->face[i].vertex[2]];
- va.x = v1->x - v0->x; va.y = v1->y - v0->y; va.z = v1->z - v0->z;
- vb.x = v2->x - v0->x; vb.y = v2->y - v0->y; vb.z = v2->z - v0->z;
- v0 = &norm[i];
- v0->x = (va.y * vb.z) - (va.z * vb.y);
- v0->y = (va.z * vb.x) - (va.x * vb.z);
- v0->z = (va.x * vb.y) - (va.y * vb.x);
- w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z));
- v0->x *= w; v0->y *= w; v0->z *= w;
- model->face[i].normal[0] = model->face[i].vertex[0] + n;
- model->face[i].normal[1] = model->face[i].vertex[1] + n;
- model->face[i].normal[2] = model->face[i].vertex[2] + n;
- }
- M3D_LOG("Generating normals");
- model->flags |= M3D_FLG_GENNORM;
- model->numvertex <<= 1;
- model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, model->numvertex * sizeof(m3dv_t));
- if(!model->vertex) goto memerr;
- memset(&model->vertex[n], 0, n * sizeof(m3dv_t));
- for(i = 0; i < model->numface; i++)
- for(j = 0; j < 3; j++) {
- v0 = &model->vertex[model->face[i].vertex[j] + n];
- v0->x += norm[i].x;
- v0->y += norm[i].y;
- v0->z += norm[i].z;
- }
- for(i = 0, v0 = &model->vertex[n]; i < n; i++, v0++) {
- w = _m3d_rsq((v0->x * v0->x) + (v0->y * v0->y) + (v0->z * v0->z));
- v0->x *= w; v0->y *= w; v0->z *= w;
- v0->skinid = M3D_UNDEF;
- }
- M3D_FREE(norm);
- }
- #endif
- if(model->numbone && model->bone && model->numskin && model->skin && model->numvertex && model->vertex) {
- #ifndef M3D_NOWEIGHTS
- M3D_LOG("Generating weight cross-reference");
- for(i = 0; i < model->numvertex; i++) {
- if(model->vertex[i].skinid < model->numskin) {
- sk = &model->skin[model->vertex[i].skinid];
- w = (M3D_FLOAT)0.0;
- for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++)
- w += sk->weight[j];
- for(j = 0; j < M3D_NUMBONE && sk->boneid[j] != M3D_UNDEF && sk->weight[j] > (M3D_FLOAT)0.0; j++) {
- sk->weight[j] /= w;
- b = &model->bone[sk->boneid[j]];
- k = b->numweight++;
- b->weight = (m3dw_t*)M3D_REALLOC(b->weight, b->numweight * sizeof(m3da_t));
- if(!b->weight) goto memerr;
- b->weight[k].vertexid = i;
- b->weight[k].weight = sk->weight[j];
- }
- }
- }
- #endif
- #ifndef M3D_NOANIMATION
- M3D_LOG("Calculating bone transformation matrices");
- for(i = 0; i < model->numbone; i++) {
- b = &model->bone[i];
- if(model->bone[i].parent == M3D_UNDEF) {
- _m3d_mat((M3D_FLOAT*)&b->mat4, &model->vertex[b->pos], &model->vertex[b->ori]);
- } else {
- _m3d_mat((M3D_FLOAT*)&r, &model->vertex[b->pos], &model->vertex[b->ori]);
- _m3d_mul((M3D_FLOAT*)&b->mat4, (M3D_FLOAT*)&model->bone[b->parent].mat4, (M3D_FLOAT*)&r);
- }
- }
- for(i = 0; i < model->numbone; i++)
- _m3d_inv((M3D_FLOAT*)&model->bone[i].mat4);
- #endif
- }
- }
- return model;
- }
- m3dtr_t *m3d_frame(m3d_t *model, M3D_INDEX actionid, M3D_INDEX frameid, m3dtr_t *skeleton)
- {
- unsigned int i;
- M3D_INDEX s = frameid;
- m3dfr_t *fr;
- if(!model || !model->numbone || !model->bone || (actionid != M3D_UNDEF && (!model->action ||
- actionid >= model->numaction || frameid >= model->action[actionid].numframe))) {
- model->errcode = M3D_ERR_UNKFRAME;
- return skeleton;
- }
- model->errcode = M3D_SUCCESS;
- if(!skeleton) {
- skeleton = (m3dtr_t*)M3D_MALLOC(model->numbone * sizeof(m3dtr_t));
- if(!skeleton) {
- model->errcode = M3D_ERR_ALLOC;
- return NULL;
- }
- goto gen;
- }
- if(actionid == M3D_UNDEF || !frameid) {
- gen: s = 0;
- for(i = 0; i < model->numbone; i++) {
- skeleton[i].boneid = i;
- skeleton[i].pos = model->bone[i].pos;
- skeleton[i].ori = model->bone[i].ori;
- }
- }
- if(actionid < model->numaction && (frameid || !model->action[actionid].frame[0].msec)) {
- for(; s <= frameid; s++) {
- fr = &model->action[actionid].frame[s];
- for(i = 0; i < fr->numtransform; i++) {
- skeleton[fr->transform[i].boneid].pos = fr->transform[i].pos;
- skeleton[fr->transform[i].boneid].ori = fr->transform[i].ori;
- }
- }
- }
- return skeleton;
- }
- #ifndef M3D_NOANIMATION
- m3db_t *m3d_pose(m3d_t *model, M3D_INDEX actionid, uint32_t msec)
- {
- unsigned int i, j, l;
- M3D_FLOAT r[16], t, c, d, s;
- m3db_t *ret;
- m3dv_t *v, *p, *f;
- m3dtr_t *tmp;
- m3dfr_t *fr;
- if(!model || !model->numbone || !model->bone) {
- model->errcode = M3D_ERR_UNKFRAME;
- return NULL;
- }
- ret = (m3db_t*)M3D_MALLOC(model->numbone * sizeof(m3db_t));
- if(!ret) {
- model->errcode = M3D_ERR_ALLOC;
- return NULL;
- }
- memcpy(ret, model->bone, model->numbone * sizeof(m3db_t));
- for(i = 0; i < model->numbone; i++)
- _m3d_inv((M3D_FLOAT*)&ret[i].mat4);
- if(!model->action || actionid >= model->numaction) {
- model->errcode = M3D_ERR_UNKFRAME;
- return ret;
- }
- msec %= model->action[actionid].durationmsec;
- model->errcode = M3D_SUCCESS;
- fr = &model->action[actionid].frame[0];
- for(j = l = 0; j < model->action[actionid].numframe && model->action[actionid].frame[j].msec <= msec; j++) {
- fr = &model->action[actionid].frame[j];
- l = fr->msec;
- for(i = 0; i < fr->numtransform; i++) {
- ret[fr->transform[i].boneid].pos = fr->transform[i].pos;
- ret[fr->transform[i].boneid].ori = fr->transform[i].ori;
- }
- }
- if(l != msec) {
- model->vertex = (m3dv_t*)M3D_REALLOC(model->vertex, (model->numvertex + 2 * model->numbone) * sizeof(m3dv_t));
- if(!model->vertex) {
- free(ret);
- model->errcode = M3D_ERR_ALLOC;
- return NULL;
- }
- tmp = (m3dtr_t*)M3D_MALLOC(model->numbone * sizeof(m3dtr_t));
- if(tmp) {
- for(i = 0; i < model->numbone; i++) {
- tmp[i].pos = ret[i].pos;
- tmp[i].ori = ret[i].ori;
- }
- fr = &model->action[actionid].frame[j % model->action[actionid].numframe];
- t = l >= fr->msec ? (M3D_FLOAT)1.0 : (M3D_FLOAT)(msec - l) / (M3D_FLOAT)(fr->msec - l);
- for(i = 0; i < fr->numtransform; i++) {
- tmp[fr->transform[i].boneid].pos = fr->transform[i].pos;
- tmp[fr->transform[i].boneid].ori = fr->transform[i].ori;
- }
- for(i = 0, j = model->numvertex; i < model->numbone; i++) {
- if(ret[i].pos != tmp[i].pos) {
- p = &model->vertex[ret[i].pos];
- f = &model->vertex[tmp[i].pos];
- v = &model->vertex[j];
- v->x = p->x + t * (f->x - p->x);
- v->y = p->y + t * (f->y - p->y);
- v->z = p->z + t * (f->z - p->z);
- ret[i].pos = j++;
- }
- if(ret[i].ori != tmp[i].ori) {
- p = &model->vertex[ret[i].ori];
- f = &model->vertex[tmp[i].ori];
- v = &model->vertex[j];
- d = p->w * f->w + p->x * f->x + p->y * f->y + p->z * f->z;
- if(d < 0) { d = -d; s = (M3D_FLOAT)-1.0; } else s = (M3D_FLOAT)1.0;
- #if 0
- a = (M3D_FLOAT)1.0 - t; b = t;
- if(d < (M3D_FLOAT)0.999999) { c = acosf(d); b = 1 / sinf(c); a = sinf(a * c) * b; b *= sinf(t * c) * s; }
- v->x = p->x * a + f->x * b;
- v->y = p->y * a + f->y * b;
- v->z = p->z * a + f->z * b;
- v->w = p->w * a + f->w * b;
- #else
- c = t - (M3D_FLOAT)0.5; t += t * c * (t - (M3D_FLOAT)1.0) * (((M3D_FLOAT)1.0904 + d * ((M3D_FLOAT)-3.2452 +
- d * ((M3D_FLOAT)3.55645 - d * (M3D_FLOAT)1.43519))) * c * c + ((M3D_FLOAT)0.848013 + d *
- ((M3D_FLOAT)-1.06021 + d * (M3D_FLOAT)0.215638)));
- v->x = p->x + t * (s * f->x - p->x);
- v->y = p->y + t * (s * f->y - p->y);
- v->z = p->z + t * (s * f->z - p->z);
- v->w = p->w + t * (s * f->w - p->w);
- d = _m3d_rsq(v->w * v->w + v->x * v->x + v->y * v->y + v->z * v->z);
- v->x *= d; v->y *= d; v->z *= d; v->w *= d;
- #endif
- ret[i].ori = j++;
- }
- }
- M3D_FREE(tmp);
- }
- }
- for(i = 0; i < model->numbone; i++) {
- if(ret[i].parent == M3D_UNDEF) {
- _m3d_mat((M3D_FLOAT*)&ret[i].mat4, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]);
- } else {
- _m3d_mat((M3D_FLOAT*)&r, &model->vertex[ret[i].pos], &model->vertex[ret[i].ori]);
- _m3d_mul((M3D_FLOAT*)&ret[i].mat4, (M3D_FLOAT*)&ret[ret[i].parent].mat4, (M3D_FLOAT*)&r);
- }
- }
- return ret;
- }
- #endif
- #endif
- #if !defined(M3D_NODUP) && (!defined(M3D_NOIMPORTER) || defined(M3D_EXPORTER))
- void m3d_free(m3d_t *model)
- {
- unsigned int i, j;
- if(!model) return;
- if(model->flags & M3D_FLG_FREERAW) M3D_FREE(model->raw);
- if(model->tmap) M3D_FREE(model->tmap);
- if(model->bone) {
- for(i = 0; i < model->numbone; i++)
- if(model->bone[i].weight)
- M3D_FREE(model->bone[i].weight);
- M3D_FREE(model->bone);
- }
- if(model->skin) M3D_FREE(model->skin);
- if(model->vertex) M3D_FREE(model->vertex);
- if(model->face) M3D_FREE(model->face);
- if(model->voxtype) {
- for(i = 0; i < model->numvoxtype; i++)
- if(model->voxtype[i].item)
- M3D_FREE(model->voxtype[i].item);
- M3D_FREE(model->voxtype);
- }
- if(model->voxel) {
- for(i = 0; i < model->numvoxel; i++)
- if(model->voxel[i].data)
- M3D_FREE(model->voxel[i].data);
- M3D_FREE(model->voxel);
- }
- if(model->shape) {
- for(i = 0; i < model->numshape; i++) {
- if(model->shape[i].cmd) {
- for(j = 0; j < model->shape[i].numcmd; j++)
- if(model->shape[i].cmd[j].arg) M3D_FREE(model->shape[i].cmd[j].arg);
- M3D_FREE(model->shape[i].cmd);
- }
- }
- M3D_FREE(model->shape);
- }
- if(model->material && !(model->flags & M3D_FLG_MTLLIB)) {
- for(i = 0; i < model->nummaterial; i++)
- if(model->material[i].prop) M3D_FREE(model->material[i].prop);
- M3D_FREE(model->material);
- }
- if(model->texture) {
- for(i = 0; i < model->numtexture; i++)
- if(model->texture[i].d) M3D_FREE(model->texture[i].d);
- M3D_FREE(model->texture);
- }
- if(model->action) {
- for(i = 0; i < model->numaction; i++) {
- if(model->action[i].frame) {
- for(j = 0; j < model->action[i].numframe; j++)
- if(model->action[i].frame[j].transform) M3D_FREE(model->action[i].frame[j].transform);
- M3D_FREE(model->action[i].frame);
- }
- }
- M3D_FREE(model->action);
- }
- if(model->label) M3D_FREE(model->label);
- if(model->inlined) M3D_FREE(model->inlined);
- if(model->extra) M3D_FREE(model->extra);
- free(model);
- }
- #endif
- #endif
- #endif
- m3d_t *apck_model(apck_t *ctx, char *name);
- #ifdef APCK_IMPLEMENTATION
- /**
- * Read in an ULEB128 number
- */
- uint8_t *apck_uleb128(uint8_t *ptr, uint64_t *value)
- {
- uint32_t shift = 0, b;
- *value = 0;
- do {
- b = *ptr++;
- *value |= ((b & 0x7f) << shift);
- shift += 7;
- } while(shift < 64 && (b & 0x80));
- return ptr;
- }
- /**
- * Calculate checksum
- */
- uint32_t apck_crc32(uint8_t *buf, uint32_t size)
- {
- static uint32_t crc32_lookup[256] = { 0 };
- uint32_t crc32_val = 0xffffffff, i, j, d;
- if(!crc32_lookup[1])
- for(i = 0; i < 256; i++)
- for(d = i, j = 0; j < 8; j++)
- crc32_lookup[i] = d = d & 1 ? (d >> 1) ^ 0xedb88320 : d >> 1;
- while(size--) crc32_val = (crc32_val >> 8) ^ crc32_lookup[(crc32_val & 0xff) ^ *buf++];
- return crc32_val ^ 0xffffffff;
- }
- /**
- * Initialize unpacker context
- */
- int apck_init(apck_t *ctx, char *engine, uint32_t version, apck_initcb_t initcb, apck_readcb_t readcb)
- {
- if(!ctx) return APCK_ERR_BADINP;
- memset(ctx, 0, sizeof(apck_t));
- if(engine) strncpy((char*)ctx->engine, engine, 12);
- ctx->version = version;
- ctx->initcb = initcb;
- ctx->readcb = readcb;
- return APCK_OK;
- }
- /**
- * Read asset from archive into a newly allocated buffer. Supported by all ciphers.
- */
- uint8_t *apck_readbuf(apck_t *ctx, uint32_t archive, uint64_t offs, uint64_t size)
- {
- uint8_t *buf;
- uint64_t len;
- if(!ctx || !size || archive >= ctx->numarchive || offs >= ctx->archives[archive].size) return NULL;
- len = (size + 255) & ~255;
- if(!(buf = (uint8_t*)malloc(len))) return NULL;
- apck_fileseek(ctx->archives[archive].f, offs);
- if((size = apck_fileread(ctx->archives[archive].f, buf, len)) && ctx->readcb)
- (*ctx->readcb)(ctx->archives[archive].enc, offs, buf, size);
- if(!size) { free(buf); buf = NULL; }
- return buf;
- }
- /**
- * Read part of archive into an existing buffer. Not all ciphers supports this.
- */
- uint64_t apck_read(apck_t *ctx, uint32_t archive, uint64_t offs, uint8_t *buf, uint64_t size)
- {
- if(!ctx || !buf || !size || archive >= ctx->numarchive || offs >= ctx->archives[archive].size) return APCK_ERR_BADINP;
- if(offs + size > ctx->archives[archive].size) size = ctx->archives[archive].size - offs;
- apck_fileseek(ctx->archives[archive].f, offs);
- if((size = apck_fileread(ctx->archives[archive].f, buf, size)) && ctx->readcb)
- (*ctx->readcb)(ctx->archives[archive].enc, offs, buf, size);
- return size;
- }
- /**
- * Merge an asset into the global Asset Directory
- */
- static int _apck_merge_asset(apck_t *ctx, char *name, uint32_t a, uint32_t j, uint32_t n, uint64_t o, uint64_t s, uint64_t c)
- {
- uint32_t k = 0;
- if(j != APCK_ATLAS)
- for(k = 0; k < ctx->numfiles[j] && strcmp(ctx->files[j][k].name, name); k++);
- if(j == APCK_ATLAS || k >= ctx->numfiles[j]) {
- k = ctx->numfiles[j]++;
- if(!(ctx->files[j] = (apck_file_t*)realloc(ctx->files[j], ctx->numfiles[j] * sizeof(apck_file_t)))) {
- DBG(("unable to allocate files[%u] for '%s' (%u entries)\n", j, name, ctx->numfiles[j]));
- ctx->numfiles[j] = 0;
- return 0;
- }
- memset(&ctx->files[j][k], 0, sizeof(apck_file_t));
- }
- if(ctx->files[j][k].buf) { free(ctx->files[j][k].buf); ctx->files[j][k].buf = NULL; }
- ctx->files[j][k].archive = a;
- ctx->files[j][k].w = ctx->files[j][k].h = 0;
- ctx->files[j][k].name = name;
- ctx->files[j][k].str = n;
- ctx->files[j][k].offs = o;
- ctx->files[j][k].size = s;
- ctx->files[j][k].comp = c;
- return 1;
- }
- /**
- * Helper to sort assets
- */
- int _apck_filecmp(const void *a, const void *b)
- {
- return strcmp(((apck_file_t*)a)->name, ((apck_file_t*)b)->name);
- }
- /**
- * Add an archive to the context
- */
- int apck_load(apck_t *ctx, char *fn)
- {
- uint64_t n, m, o, s, c;
- uint32_t a, i, j, k = 0;
- uint64_t size;
- uint8_t *comp, *orig, *ptr, *end;
- apck_hdr_t hdr;
- void *f, *enc;
- char *str, *name;
- if(!ctx || !fn || !*fn) return APCK_ERR_BADINP;
- /* get header */
- if(!(f = apck_fileopen(fn, &size))) return APCK_ERR_BADPCK;
- if(!apck_fileread(f, &hdr, sizeof(hdr)) || memcmp(hdr.magic, APCK_MAGIC, 4) ||
- hdr.size < 9 || hdr.hdr_size - sizeof(apck_hdr_t) > hdr.size ||
- (ctx->engine[0] && memcmp(ctx->engine, hdr.engine, 12)) || (ctx->version && ctx->version < hdr.version) ||
- (*((uint64_t*)hdr.enckey) && (!ctx->initcb || !ctx->readcb))) {
- apck_fileclose(f);
- return APCK_ERR_BADPCK;
- }
- if(!(comp = (uint8_t*)malloc(hdr.hdr_size - sizeof(apck_hdr_t)))) {
- apck_fileclose(f);
- return APCK_ERR_NOMEM;
- }
- if(!(orig = (uint8_t*)malloc(hdr.size))) {
- free(comp);
- apck_fileclose(f);
- return APCK_ERR_NOMEM;
- }
- /* we can't use apck_read yet, because the archive isn't registered yet */
- enc = *((uint64_t*)hdr.enckey) ? (*ctx->initcb)(hdr.enckey) : NULL;
- if(!apck_fileread(f, comp, hdr.hdr_size - sizeof(apck_hdr_t)) ||
- (enc && (*ctx->readcb)(enc, sizeof(apck_hdr_t), comp, hdr.hdr_size - sizeof(apck_hdr_t))) ||
- stbi_zlib_decode_buffer((char*)orig, (int)hdr.size, (char*)comp, (int)(hdr.hdr_size - sizeof(apck_hdr_t))) < 1 ||
- apck_crc32(orig, hdr.size) != hdr.chksum || *((uint32_t*)orig) < 4 || *((uint32_t*)orig) >= hdr.size) {
- if(enc) free(enc);
- free(comp);
- free(orig);
- apck_fileclose(f);
- return APCK_ERR_BADPCK;
- }
- free(comp);
- /* add the archive to the list */
- a = ctx->numarchive++;
- if(!(ctx->archives = (apck_archive_t*)realloc(ctx->archives, ctx->numarchive * sizeof(apck_archive_t)))) {
- ctx->numarchive = 0;
- return APCK_ERR_NOMEM;
- }
- ctx->archives[a].f = f;
- ctx->archives[a].size = size;
- ctx->archives[a].str = orig;
- ctx->archives[a].enc = enc;
- ctx->archives[a].aidx = ctx->numfiles[APCK_ATLAS];
- /* merge its asset directory with the existing one */
- ptr = orig + *((uint32_t*)orig);
- end = orig + hdr.size;
- for(j = 0; j < APCK_NUMTYPES && ptr < end; j++) {
- ptr = apck_uleb128(ptr, &m);
- for(i = 0; i < m && ptr < end; i++) {
- ptr = apck_uleb128(ptr, &n);
- ptr = apck_uleb128(ptr, &o);
- ptr = apck_uleb128(ptr, &s);
- ptr = apck_uleb128(ptr, &c);
- o += hdr.hdr_size;
- name = (char*)orig + n;
- if(j < APCK_FONT) {
- /* locales need special treatment */
- if(!i) {
- for(k = 0; k < APCK_FONT && ctx->files[k] && strcmp(ctx->files[k][0].name, name); k++);
- if(k < APCK_FONT) {
- if(!ctx->files[k]) {
- if(!_apck_merge_asset(ctx, name, a, k, n, 0, 0, 0) || !ctx->files[k]) k = APCK_FONT;
- }
- if(k < APCK_FONT && (comp = apck_readbuf(ctx, a, o, c))) {
- if((str = (char*)malloc(s))) {
- if(stbi_zlib_decode_buffer((char*)str, (int)s, (char*)comp, (int)c) < 1 ||
- !_apck_merge_locale(ctx, k, str, s)) {
- k = APCK_FONT; DBG(("unable to uncompress locale '%s' from '%s'\n", name, fn));
- }
- free(str);
- } else { k = APCK_FONT; DBG(("unable to allocate locale '%s' from '%s' (%u bytes)\n", name, fn, (uint32_t)s)); }
- free(comp);
- } else { k = APCK_FONT; DBG(("unable to read locale '%s' from '%s'\n", name, fn)); }
- }
- } else
- if(k < APCK_FONT) {
- /* voices and images with text for this locale */
- _apck_merge_asset(ctx, name, a, k, n, o, s, c);
- }
- } else {
- /* every other asset */
- _apck_merge_asset(ctx, name, a, j, n, o, s, c);
- }
- }
- }
- /* sort assets by name so that we can do an O(log2) search later */
- for(j = 0; j < APCK_FONT; j++)
- if(ctx->files[j] && ctx->numfiles[j] > 1)
- qsort(&ctx->files[j][1], ctx->numfiles[j] - 1, sizeof(apck_file_t), _apck_filecmp);
- for(; j < APCK_NUMTYPES; j++)
- if(ctx->files[j] && ctx->numfiles[j] && j != APCK_ATLAS)
- qsort(ctx->files[j], ctx->numfiles[j], sizeof(apck_file_t), _apck_filecmp);
- return APCK_OK;
- }
- /**
- * Free buffer for one particular asset
- */
- void _apck_asset_free(apck_file_t *file, int type)
- {
- if(file && file->buf) {
- switch(type) {
- case APCK_MODEL: m3d_free((m3d_t*)file->buf); break;
- case APCK_SPRITE: apck_sprite_free((apck_sprite_t*)file->buf); break;
- case APCK_MAP: apck_map_free((apck_map_t*)file->buf); break;
- default: free(file->buf); break;
- }
- file->buf = NULL;
- }
- }
- /**
- * Free all resources
- */
- int apck_free(apck_t *ctx)
- {
- uint32_t i, j;
- if(!ctx) return APCK_ERR_BADINP;
- if(ctx->archives) {
- for(i = 0; i < ctx->numarchive; i++) {
- if(ctx->archives[i].f) apck_fileclose(ctx->archives[i].f);
- if(ctx->archives[i].str) free(ctx->archives[i].str);
- if(ctx->archives[i].enc) free(ctx->archives[i].enc);
- }
- free(ctx->archives);
- }
- for(j = 0; j < APCK_NUMTYPES; j++)
- if(ctx->files[j]) {
- for(i = 0; i < ctx->numfiles[j]; i++)
- _apck_asset_free(&ctx->files[j][i], j);
- free(ctx->files[j]);
- }
- for(i = 0; i < APCK_FONT; i++)
- if(ctx->msgstr[i]) free(ctx->msgstr[i]);
- if(ctx->font) {
- ssfn_free(ctx->font);
- free(ctx->font);
- }
- memset(ctx, 0, sizeof(apck_t));
- return APCK_OK;
- }
- /**
- * Look up an asset in the Global Asset Directory
- */
- apck_file_t *apck_lookup(apck_t *ctx, int type, char *name)
- {
- apck_file_t *dir;
- int s, e, h, m;
- if(!ctx || type < 0 || type >= APCK_NUMTYPES || !name || !*name || !ctx->files[type] || !ctx->numfiles[type])
- return NULL;
- /* use binary search */
- dir = ctx->files[type];
- s = !(type >= APCK_FONT);
- e = ctx->numfiles[type] - 1;
- while(s <= e) {
- h = ((e + s) >> 1);
- m = strcmp(dir[h].name, name);
- if(!m) return &dir[h];
- if(m > 0) e = h - 1; else s = h + 1;
- }
- return NULL;
- }
- /**
- * Free internal cache of one particular asset
- */
- int apck_release(apck_t *ctx, int type, char *name)
- {
- if(!ctx || type < 0 || type >= APCK_NUMTYPES || !name || !*name)
- return APCK_ERR_BADINP;
- _apck_asset_free(apck_lookup(ctx, type, name), type);
- return APCK_OK;
- }
- /**
- * Look up and return any arbitrary asset
- */
- uint8_t *apck_asset(apck_t *ctx, int type, char *name, uint64_t *size)
- {
- apck_file_t *file = NULL;
- uint8_t *buf, *comp;
- if(size) *size = 0;
- if(!ctx || type > APCK_MAP || type >= APCK_NUMTYPES || !name || !*name)
- return NULL;
- if((file = apck_lookup(ctx, type, name))) {
- /* we have this asset, let's see if we have cached its contents already */
- if(!file->buf) {
- if(file->size && (comp = apck_readbuf(ctx, file->archive, file->offs, file->comp ? file->comp : file->size))) {
- if(file->comp) {
- /* we got the data from the archive, uncompress it */
- if((buf = (uint8_t*)malloc(file->size))) {
- if(stbi_zlib_decode_buffer((char*)buf, (int)file->size, (char*)comp, (int)file->comp) < 1) {
- DBG(("unable to uncompress asset '%s'\n", name));
- free(buf);
- file->size = file->comp = 0;
- } else
- file->buf = buf;
- } else { DBG(("unable to allocate asset '%s' (%u bytes)\n", name, (uint32_t)file->size)); }
- free(comp);
- } else file->buf = comp;
- } else { DBG(("unable to read asset '%s'\n", name)); }
- }
- if(size) *size = file->size;
- return (uint8_t*)file->buf;
- }
- return NULL;
- }
- /**
- * Look up and set the font to be used by apck_text()
- */
- int apck_font(apck_t *ctx, char *name)
- {
- apck_file_t *file = NULL;
- uint8_t *buf, *comp;
- if(!ctx || !name || !*name)
- return APCK_ERR_BADINP;
- if(!ctx->font) {
- if(!(ctx->font = (ssfn_t*)malloc(sizeof(ssfn_t))))
- return APCK_ERR_NOMEM;
- memset(ctx->font, 0, sizeof(ssfn_t));
- } else
- ssfn_free(ctx->font);
- if((file = apck_lookup(ctx, APCK_FONT, name))) {
- /* we have this asset, let's see if we have cached its contents already */
- if(!file->buf) {
- if(file->comp && (comp = apck_readbuf(ctx, file->archive, file->offs, file->comp))) {
- /* we got the data from the archive, uncompress it */
- if((buf = (uint8_t*)malloc(file->size))) {
- if(stbi_zlib_decode_buffer((char*)buf, (int)file->size, (char*)comp, (int)file->comp) < 1 || memcmp(buf, "SFN2", 4)) {
- DBG(("unable to uncompress font '%s'\n", name));
- file->size = file->comp = 0;
- free(buf);
- } else
- file->buf = buf;
- } else { DBG(("unable to allocate font '%s' (%u bytes)\n", name, (uint32_t)file->size)); }
- free(comp);
- } else { DBG(("unable to read font '%s'\n", name)); }
- }
- if(ctx->font && file->buf)
- ssfn_load(ctx->font, file->buf);
- return APCK_OK;
- }
- return APCK_ERR_BADINP;
- }
- /**
- * Render localized text and return a pixel buffer as if the were an asset stored in archive
- */
- uint32_t *apck_text(apck_t *ctx, char *msgid, uint32_t color, int fontstyle, int fontsize, int *w, int *h)
- {
- ssfn_buf_t buf = { 0 };
- char *msgstr;
- int ret;
- if(w) *w = 0;
- if(h) *h = 0;
- if(!ctx || !ctx->font || !(color & 0xfc000000) || !(msgstr = apck_msgstr(ctx, msgid)) ||
- ssfn_select(ctx->font, SSFN_FAMILY_ANY, NULL, fontstyle | SSFN_STYLE_NOCACHE, fontsize) != SSFN_OK ||
- ssfn_bbox(ctx->font, msgstr, (int*)&buf.w, (int*)&buf.h, (int*)&buf.x, (int*)&buf.y) != SSFN_OK)
- return NULL;
- buf.fg = color;
- buf.p = buf.w * sizeof(uint32_t);
- if((buf.ptr = (uint8_t*)malloc(buf.p * buf.h))) {
- memset(buf.ptr, 0, buf.p * buf.h);
- while((ret = ssfn_render(ctx->font, &buf, msgstr)) > 0)
- msgstr += ret;
- if(w) *w = buf.w;
- if(h) *h = buf.h;
- }
- return (uint32_t*)buf.ptr;
- }
- /**
- * Look up and return a decoded 3D model
- */
- m3d_t *apck_model(apck_t *ctx, char *name)
- {
- apck_file_t *file = NULL;
- uint8_t *buf, *comp;
- if(!ctx || !name || !*name)
- return NULL;
- if((file = apck_lookup(ctx, APCK_MODEL, name))) {
- /* we have this asset, let's see if we have cached its contents already */
- if(!file->buf) {
- if(file->comp && (comp = apck_readbuf(ctx, file->archive, file->offs, file->comp))) {
- /* we got the data from the archive, uncompress it */
- if((buf = (uint8_t*)malloc(file->size))) {
- if(stbi_zlib_decode_buffer((char*)buf, (int)file->size, (char*)comp, (int)file->comp) < 1) {
- DBG(("unable to uncompress model '%s'\n", name));
- file->size = file->comp = 0;
- } else
- if(!(file->buf = (uint8_t*)m3d_load(buf, NULL, NULL, NULL))) {
- DBG(("unable to decode model '%s'\n", name));
- file->size = file->comp = 0;
- }
- free(buf);
- } else { DBG(("unable to allocate model '%s' (%u bytes)\n", name, (uint32_t)file->size)); }
- free(comp);
- } else { DBG(("unable to read model '%s'\n", name)); }
- }
- return (m3d_t*)file->buf;
- }
- return NULL;
- }
- /**
- * Look up and return a decoded image asset
- */
- uint32_t *apck_image(apck_t *ctx, int type, char *name, int *w, int *h)
- {
- apck_file_t *file = NULL;
- uint8_t *buf;
- int p, i;
- if(w) *w = 0;
- if(h) *h = 0;
- if(!ctx || (type != APCK_IMAGE && type != APCK_ATLAS) || !name || !*name)
- return NULL;
- if(type == APCK_ATLAS) {
- /* atlases are generated so they don't have a real name, they use index instead */
- i = atoi(name) - 1;
- if(ctx->files[APCK_ATLAS] && i >= 0 && (uint32_t)i < ctx->numfiles[APCK_ATLAS])
- file = &ctx->files[APCK_ATLAS][i];
- } else {
- /* for images, try localized images first */
- if(ctx->locale < APCK_FONT && ctx->files[ctx->locale])
- file = apck_lookup(ctx, ctx->locale, name);
- if(!file) file = apck_lookup(ctx, type, name);
- }
- if(file) {
- /* we have this asset, let's see if we have cached its contents already */
- if(!file->buf) {
- if(file->size && (buf = apck_readbuf(ctx, file->archive, file->offs, file->size))) {
- if(!(file->buf = (uint8_t*)stbi_load_from_memory(buf, file->size, &file->w, &file->h, &p, 4))) {
- DBG(("unable to decode image asset '%s'\n", name));
- file->size = file->comp = 0;
- }
- free(buf);
- } else { DBG(("unable to read image asset '%s'\n", name)); }
- }
- /* extra check for images */
- if(!file->buf || file->w < 1 || file->h < 1) return NULL;
- /* return the decoded asset */
- if(w) *w = file->w;
- if(h) *h = file->h;
- return (uint32_t*)file->buf;
- }
- return NULL;
- }
- /**
- * Look up and return a decoded audio asset
- */
- int16_t *apck_audio(apck_t *ctx, int type, char *name, int *numsamples, int *channels)
- {
- apck_file_t *file = NULL;
- uint8_t *buf;
- int ch, hz;
- if(numsamples) *numsamples = 0;
- if(channels) *channels = 0;
- if(!ctx || (type != APCK_BGM && type != APCK_SFX) || !name || !*name)
- return NULL;
- /* for sound effects, try localized voices first */
- if(type == APCK_SFX && ctx->locale < APCK_FONT && ctx->files[ctx->locale])
- file = apck_lookup(ctx, ctx->locale, name);
- if(!file) file = apck_lookup(ctx, type, name);
- if(file) {
- /* we have this asset, let's see if we have cached its contents already */
- if(!file->buf) {
- if(file->size && (buf = apck_readbuf(ctx, file->archive, file->offs, file->size))) {
- if(!(file->w = APCK_OGG(buf, file->size, &ch, &hz, (int16_t**)&file->buf))) {
- DBG(("unable to decode audio asset '%s'\n", name));
- file->size = file->comp = 0;
- } else {
- file->w *= ch;
- file->h = -ch;
- }
- free(buf);
- } else { DBG(("unable to read audio asset '%s'\n", name)); }
- }
- /* extra check for audio */
- if(!file->buf || file->w < 1 || file->h > -1) return NULL;
- /* return the decoded asset */
- if(numsamples) *numsamples = file->w;
- if(channels) *channels = -file->h;
- return (int16_t*)file->buf;
- }
- return NULL;
- }
- /**
- * Look up and return a decoded sprite asset
- */
- apck_sprite_t *apck_sprite(apck_t *ctx, char *name)
- {
- apck_file_t *file = NULL;
- uint8_t *buf, *comp;
- if(!ctx || !name || !*name)
- return NULL;
- if((file = apck_lookup(ctx, APCK_SPRITE, name))) {
- /* we have this asset, let's see if we have cached its contents already */
- if(!file->buf) {
- if(file->comp && (comp = apck_readbuf(ctx, file->archive, file->offs, file->comp))) {
- if((buf = (uint8_t*)malloc(file->size))) {
- if(stbi_zlib_decode_buffer((char*)buf, (int)file->size, (char*)comp, (int)file->comp) < 1 ||
- !(file->buf = (uint8_t*)apck_sprite_decode(ctx->archives[file->archive].aidx,
- ctx->archives[file->archive].str, buf, file->size))) {
- DBG(("unable to uncompress sprite '%s'\n", name));
- file->size = file->comp = 0;
- }
- free(buf);
- } else { DBG(("unable to allocate sprite '%s' (%u bytes)\n", name, (uint32_t)file->size)); }
- free(comp);
- } else { DBG(("unable to read sprite asset '%s'\n", name)); }
- }
- return (apck_sprite_t*)file->buf;
- }
- return NULL;
- }
- /**
- * Look up and return a decoded map asset
- */
- apck_map_t *apck_map(apck_t *ctx, char *name)
- {
- apck_file_t *file = NULL;
- uint8_t *buf, *comp;
- if(!ctx || !name || !*name)
- return NULL;
- if((file = apck_lookup(ctx, APCK_MAP, name))) {
- /* we have this asset, let's see if we have cached its contents already */
- if(!file->buf) {
- if(file->comp && (comp = apck_readbuf(ctx, file->archive, file->offs, file->comp))) {
- if((buf = (uint8_t*)malloc(file->size))) {
- if(stbi_zlib_decode_buffer((char*)buf, (int)file->size, (char*)comp, (int)file->comp) < 1 ||
- !(file->buf = (uint8_t*)apck_map_decode(ctx->archives[file->archive].str, buf, file->size))) {
- DBG(("unable to uncompress map '%s'\n", name));
- file->size = file->comp = 0;
- }
- free(buf);
- } else { DBG(("unable to allocate map '%s' (%u bytes)\n", name, (uint32_t)file->size)); }
- free(comp);
- } else { DBG(("unable to read map asset '%s'\n", name)); }
- }
- return (apck_map_t*)file->buf;
- }
- return NULL;
- }
- #endif /* APCK_IMPLEMENTATION */
- #ifdef __cplusplus
- }
- #endif
- #endif /* APIC_H */
|