tigr.c 199 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609
  1. //////// Start of inlined file: tigr_amalgamated.c ////////
  2. #include "tigr.h"
  3. //////// Start of inlined file: tigr_internal.h ////////
  4. // can't use pragma once here because this file probably will endup in .c
  5. #ifndef __TIGR_INTERNAL_H__
  6. #define __TIGR_INTERNAL_H__
  7. #define _CRT_SECURE_NO_WARNINGS NOPE
  8. // Graphics configuration.
  9. #ifndef TIGR_HEADLESS
  10. #define TIGR_GAPI_GL
  11. // Calculates the biggest scale that a bitmap can fit into an area at.
  12. int tigrCalcScale(int bmpW, int bmpH, int areaW, int areaH);
  13. #endif
  14. // Creates a new bitmap, with extra payload bytes.
  15. Tigr* tigrBitmap2(int w, int h, int extra);
  16. // Resizes an existing bitmap.
  17. void tigrResize(Tigr* bmp, int w, int h);
  18. // Calculates a new scale, taking minimum-scale flags into account.
  19. int tigrEnforceScale(int scale, int flags);
  20. // Calculates the correct position for a bitmap to fit into a window.
  21. void tigrPosition(Tigr* bmp, int scale, int windowW, int windowH, int out[4]);
  22. // ----------------------------------------------------------
  23. #ifdef _WIN32
  24. #define WIN32_LEAN_AND_MEAN
  25. #include <windows.h>
  26. #endif
  27. #if !defined(TIGR_HEADLESS) && __linux__ && !__ANDROID__
  28. #include <X11/X.h>
  29. #include <X11/Xlib.h>
  30. #endif
  31. #ifdef __APPLE__
  32. #include "TargetConditionals.h"
  33. #if TARGET_OS_IPHONE
  34. #define __IOS__ 1
  35. #else
  36. #define __MACOS__ 1
  37. #endif
  38. #endif
  39. #ifdef TIGR_GAPI_GL
  40. #if __MACOS__
  41. #define GL_SILENCE_DEPRECATION
  42. #include <OpenGL/gl3.h>
  43. #endif
  44. #ifdef _WIN32
  45. #include <GL/gl.h>
  46. #endif
  47. #if __linux__ && !__ANDROID__
  48. #define GL_GLEXT_PROTOTYPES
  49. #include <GL/gl.h>
  50. #include <GL/glx.h>
  51. #endif
  52. #if __ANDROID__
  53. #include <EGL/egl.h>
  54. #include <GLES3/gl3.h>
  55. #endif
  56. #if __IOS__
  57. #define GLES_SILENCE_DEPRECATION
  58. #include <OpenGLES/ES3/gl.h>
  59. #endif
  60. typedef struct {
  61. #ifdef _WIN32
  62. HGLRC hglrc;
  63. HDC dc;
  64. #endif
  65. #ifdef __APPLE__
  66. void* glContext;
  67. #endif
  68. GLuint tex[2];
  69. GLuint vao;
  70. GLuint program;
  71. GLuint uniform_projection;
  72. GLuint uniform_model;
  73. GLuint uniform_parameters;
  74. int gl_legacy;
  75. int gl_user_opengl_rendering;
  76. } GLStuff;
  77. #endif
  78. #define MAX_TOUCH_POINTS 10
  79. typedef struct {
  80. int shown, closed;
  81. #ifdef TIGR_GAPI_GL
  82. GLStuff gl;
  83. #ifdef _WIN32
  84. wchar_t* wtitle;
  85. DWORD dwStyle;
  86. RECT oldPos;
  87. #endif
  88. #ifdef __linux__
  89. #if __ANDROID__
  90. EGLContext context;
  91. #else
  92. Display* dpy;
  93. Window win;
  94. GLXContext glc;
  95. XIC ic;
  96. #endif // __ANDROID__
  97. #endif // __linux__
  98. #endif // TIGR_GAPI_GL
  99. Tigr* widgets;
  100. int widgetsWanted;
  101. unsigned char widgetAlpha;
  102. float widgetsScale;
  103. float p1, p2, p3, p4;
  104. int flags;
  105. int scale;
  106. int pos[4];
  107. int lastChar;
  108. char keys[256], prev[256];
  109. #if defined(__ANDROID__)
  110. char released[256];
  111. #endif // __ANDROID__
  112. #if defined(__MACOS__)
  113. int mouseInView;
  114. int mouseButtons;
  115. double frameTime;
  116. #endif // __MACOS__
  117. #if defined(__linux__) || defined(__IOS__)
  118. int mouseButtons;
  119. int mouseX;
  120. int mouseY;
  121. #endif // __linux__ __IOS__
  122. #if defined(__ANDROID__) || defined(__IOS__)
  123. int numTouchPoints;
  124. TigrTouchPoint touchPoints[MAX_TOUCH_POINTS];
  125. #endif // __ANDROID__ __IOS__
  126. #if defined(_WIN32) || defined(__linux__) || defined(__MACOS__)
  127. float scrollDeltaX;
  128. float scrollDeltaY;
  129. #endif // _WIN32 __linux__ __MACOS__
  130. } TigrInternal;
  131. // ----------------------------------------------------------
  132. TigrInternal* tigrInternal(Tigr* bmp);
  133. void tigrGAPICreate(Tigr* bmp);
  134. void tigrGAPIDestroy(Tigr* bmp);
  135. int tigrGAPIBegin(Tigr* bmp);
  136. int tigrGAPIEnd(Tigr* bmp);
  137. void tigrGAPIPresent(Tigr* bmp, int w, int h);
  138. #endif
  139. //////// End of inlined file: tigr_internal.h ////////
  140. //////// Start of inlined file: tigr_upscale_gl_vs.h ////////
  141. #ifndef __TIGR_UPSCALE_GL_VS_H__
  142. #define __TIGR_UPSCALE_GL_VS_H__
  143. //////// Start of inlined file: tigr_glsl_hdr.h ////////
  144. #ifndef __TIGR_GLSL_HDR_H__
  145. #define __TIGR_GLSL_HDR_H__
  146. #if __ANDROID__ || __IOS__
  147. #define GLSL_VERSION_HEADER \
  148. "#version 300 es\n" \
  149. "precision mediump float;\n"
  150. #else
  151. #define GLSL_VERSION_HEADER "#version 330 core\n"
  152. #endif
  153. #endif // __TIGR_GLSL_HDR_H__
  154. //////// End of inlined file: tigr_glsl_hdr.h ////////
  155. // clang-format off
  156. const char tigr_upscale_gl_vs[] = {
  157. GLSL_VERSION_HEADER
  158. "layout (location = 0) in vec2 pos_in;"
  159. "layout (location = 1) in vec2 uv_in;"
  160. "out vec2 uv;"
  161. "uniform mat4 model;"
  162. "uniform mat4 projection;"
  163. "void main()"
  164. "{"
  165. " uv = uv_in;"
  166. " gl_Position = projection * model * vec4(pos_in, 0.0, 1.0);"
  167. "}"
  168. };
  169. // clang-format on
  170. const int tigr_upscale_gl_vs_size = (int)sizeof(tigr_upscale_gl_vs) - 1;
  171. #endif
  172. //////// End of inlined file: tigr_upscale_gl_vs.h ////////
  173. //////// Start of inlined file: tigr_upscale_gl_fs.h ////////
  174. #ifndef __TIGR_UPSCALE_GL_FS_H__
  175. #define __TIGR_UPSCALE_GL_FS_H__
  176. //#include "tigr_glsl_hdr.h"
  177. // clang-format off
  178. const char tigr_upscale_gl_fs[] = {
  179. GLSL_VERSION_HEADER
  180. "in vec2 uv;"
  181. "out vec4 color;"
  182. "uniform sampler2D image;"
  183. "uniform vec4 parameters;"
  184. "void fxShader(out vec4 color, in vec2 coord);"
  185. "void main()"
  186. "{"
  187. " fxShader(color, uv);"
  188. "}\n"
  189. };
  190. // clang-format on
  191. const int tigr_upscale_gl_fs_size = (int)sizeof(tigr_upscale_gl_fs) - 1;
  192. // clang-format off
  193. const char tigr_default_fx_gl_fs[] = {
  194. "void fxShader(out vec4 color, in vec2 uv) {"
  195. " vec2 tex_size = vec2(textureSize(image, 0));"
  196. " vec2 uv_blur = mix(floor(uv * tex_size) + 0.5, uv * tex_size, parameters.xy) / tex_size;"
  197. " vec4 c = texture(image, uv_blur);"
  198. " c.rgb *= mix(0.5, 1.0 - fract(uv.y * tex_size.y), parameters.z) * 2.0; //scanline\n"
  199. " c = mix(vec4(0.5), c, parameters.w); //contrast\n"
  200. " color = c;"
  201. "}"
  202. };
  203. // clang-format on
  204. const int tigr_default_fx_gl_fs_size = (int)sizeof(tigr_default_fx_gl_fs) - 1;
  205. #endif
  206. //////// End of inlined file: tigr_upscale_gl_fs.h ////////
  207. //////// Start of inlined file: tigr_bitmaps.c ////////
  208. //#include "tigr_internal.h"
  209. #include <stdlib.h>
  210. #include <string.h>
  211. // Expands 0-255 into 0-256
  212. #define EXPAND(X) ((X) + ((X) > 0))
  213. #define CLIP0(CX, X, X2, W) \
  214. if (X < CX) { \
  215. int D = CX - X; \
  216. W -= D; \
  217. X2 += D; \
  218. X += D; \
  219. }
  220. #define CLIP1(X, DW, W) \
  221. if (X + W > DW) \
  222. W = DW - X;
  223. #define CLIP() \
  224. CLIP0(dst->cx, dx, sx, w); \
  225. CLIP0(dst->cy, dy, sy, h); \
  226. CLIP0(0, sx, dx, w); \
  227. CLIP0(0, sy, dy, h); \
  228. CLIP1(dx, dst->cx + cw, w); \
  229. CLIP1(dy, dst->cy + ch, h); \
  230. CLIP1(sx, src->w, w); \
  231. CLIP1(sy, src->h, h); \
  232. if (w <= 0 || h <= 0) \
  233. return
  234. Tigr* tigrBitmap2(int w, int h, int extra) {
  235. Tigr* tigr = (Tigr*)calloc(1, sizeof(Tigr) + extra);
  236. tigr->w = w;
  237. tigr->h = h;
  238. tigr->cw = -1;
  239. tigr->ch = -1;
  240. tigr->pix = (TPixel*)calloc(w * h, sizeof(TPixel));
  241. tigr->blitMode = TIGR_BLEND_ALPHA;
  242. return tigr;
  243. }
  244. Tigr* tigrBitmap(int w, int h) {
  245. return tigrBitmap2(w, h, 0);
  246. }
  247. #ifdef TIGR_HEADLESS
  248. void tigrFree(Tigr* bmp) {
  249. free(bmp->pix);
  250. free(bmp);
  251. }
  252. #endif // TIGR_HEADLESS
  253. void tigrResize(Tigr* bmp, int w, int h) {
  254. if (bmp->w == w && bmp->h == h) {
  255. return;
  256. }
  257. int y, cw, ch;
  258. TPixel* newpix = (TPixel*)calloc(w * h, sizeof(TPixel));
  259. cw = (w < bmp->w) ? w : bmp->w;
  260. ch = (h < bmp->h) ? h : bmp->h;
  261. // Copy any old data across.
  262. for (y = 0; y < ch; y++)
  263. memcpy(newpix + y * w, bmp->pix + y * bmp->w, cw * sizeof(TPixel));
  264. free(bmp->pix);
  265. bmp->pix = newpix;
  266. bmp->w = w;
  267. bmp->h = h;
  268. }
  269. #ifndef TIGR_HEADLESS
  270. int tigrCalcScale(int bmpW, int bmpH, int areaW, int areaH) {
  271. if (bmpW == 0 || bmpH == 0) {
  272. tigrError(0, "Invalid bitmap size, (%dx%d)", bmpW, bmpH);
  273. }
  274. // We want it as big as possible in the window, but still
  275. // maintaining the correct aspect ratio, and always
  276. // having an integer pixel size.
  277. int scale = 0;
  278. for (;;) {
  279. scale++;
  280. if (bmpW * scale > areaW || bmpH * scale > areaH) {
  281. scale--;
  282. break;
  283. }
  284. }
  285. return (scale > 1) ? scale : 1;
  286. }
  287. #endif // TIGR_HEADLESS
  288. int tigrEnforceScale(int scale, int flags) {
  289. if ((flags & TIGR_4X) && scale < 4)
  290. scale = 4;
  291. if ((flags & TIGR_3X) && scale < 3)
  292. scale = 3;
  293. if ((flags & TIGR_2X) && scale < 2)
  294. scale = 2;
  295. return scale;
  296. }
  297. void tigrPosition(Tigr* bmp, int scale, int windowW, int windowH, int out[4]) {
  298. // Center the image on screen at this scale.
  299. out[0] = (windowW - bmp->w * scale) / 2;
  300. out[1] = (windowH - bmp->h * scale) / 2;
  301. out[2] = out[0] + bmp->w * scale;
  302. out[3] = out[1] + bmp->h * scale;
  303. }
  304. void tigrClear(Tigr* bmp, TPixel color) {
  305. int count = bmp->w * bmp->h;
  306. int n;
  307. for (n = 0; n < count; n++)
  308. bmp->pix[n] = color;
  309. }
  310. void tigrFill(Tigr* bmp, int x, int y, int w, int h, TPixel color) {
  311. TPixel* td;
  312. int dt, i;
  313. if (x < 0) {
  314. w += x;
  315. x = 0;
  316. }
  317. if (y < 0) {
  318. h += y;
  319. y = 0;
  320. }
  321. if (x + w > bmp->w) {
  322. w = bmp->w - x;
  323. }
  324. if (y + h > bmp->h) {
  325. h = bmp->h - y;
  326. }
  327. if (w <= 0 || h <= 0)
  328. return;
  329. td = &bmp->pix[y * bmp->w + x];
  330. dt = bmp->w;
  331. do {
  332. for (i = 0; i < w; i++)
  333. td[i] = color;
  334. td += dt;
  335. } while (--h);
  336. }
  337. void tigrLine(Tigr* bmp, int x0, int y0, int x1, int y1, TPixel color) {
  338. int sx, sy, dx, dy, err, e2;
  339. dx = abs(x1 - x0);
  340. dy = abs(y1 - y0);
  341. if (x0 < x1)
  342. sx = 1;
  343. else
  344. sx = -1;
  345. if (y0 < y1)
  346. sy = 1;
  347. else
  348. sy = -1;
  349. err = dx - dy;
  350. do {
  351. tigrPlot(bmp, x0, y0, color);
  352. e2 = 2 * err;
  353. if (e2 > -dy) {
  354. err -= dy;
  355. x0 += sx;
  356. }
  357. if (e2 < dx) {
  358. err += dx;
  359. y0 += sy;
  360. }
  361. } while (x0 != x1 || y0 != y1);
  362. }
  363. void tigrFillRect(Tigr* bmp, int x, int y, int w, int h, TPixel color) {
  364. x += 1;
  365. y += 1;
  366. w -= 2;
  367. h -= 2;
  368. int cx = bmp->cx;
  369. int cy = bmp->cy;
  370. int cw = bmp->cw >= 0 ? bmp->cw : bmp->w;
  371. int ch = bmp->ch >= 0 ? bmp->ch : bmp->h;
  372. if (x < cx) {
  373. w += (x - cx);
  374. x = cx;
  375. }
  376. if (y < cy) {
  377. h += (y - cy);
  378. y = cy;
  379. }
  380. if (x + w > cx + cw) {
  381. w -= (x + w) - (cx + cw);
  382. }
  383. if (y + h > cy + ch) {
  384. h -= (y + h) - (cy + ch);
  385. }
  386. if (w <= 0 || h <= 0)
  387. return;
  388. TPixel* td = &bmp->pix[y * bmp->w + x];
  389. int dt = bmp->w;
  390. int xa = EXPAND(color.a);
  391. int a = xa * xa;
  392. do {
  393. for (int i = 0; i < w; i++) {
  394. td[i].r += (unsigned char)((color.r - td[i].r) * a >> 16);
  395. td[i].g += (unsigned char)((color.g - td[i].g) * a >> 16);
  396. td[i].b += (unsigned char)((color.b - td[i].b) * a >> 16);
  397. td[i].a += (bmp->blitMode) * (unsigned char)((color.a - td[i].a) * a >> 16);
  398. }
  399. td += dt;
  400. } while (--h);
  401. }
  402. void tigrRect(Tigr* bmp, int x, int y, int w, int h, TPixel color) {
  403. int x1, y1;
  404. if (w <= 0 || h <= 0) {
  405. return;
  406. }
  407. if (w == 1) {
  408. tigrLine(bmp, x, y, x, y + h, color);
  409. } else if (h == 1) {
  410. tigrLine(bmp, x, y, x + w, y, color);
  411. } else {
  412. x1 = x + w - 1;
  413. y1 = y + h - 1;
  414. tigrLine(bmp, x, y, x1, y, color);
  415. tigrLine(bmp, x1, y, x1, y1, color);
  416. tigrLine(bmp, x1, y1, x, y1, color);
  417. tigrLine(bmp, x, y1, x, y, color);
  418. }
  419. }
  420. void tigrFillCircle(Tigr* bmp, int x0, int y0, int r, TPixel color) {
  421. if (r <= 0) {
  422. return;
  423. }
  424. int E = 1 - r;
  425. int dx = 0;
  426. int dy = -2 * r;
  427. int x = 0;
  428. int y = r;
  429. tigrLine(bmp, x0 - r + 1, y0, x0 + r, y0, color);
  430. while (x < y - 1) {
  431. x++;
  432. if (E >= 0) {
  433. y--;
  434. dy += 2;
  435. E += dy;
  436. tigrLine(bmp, x0 - x + 1, y0 + y, x0 + x, y0 + y, color);
  437. tigrLine(bmp, x0 - x + 1, y0 - y, x0 + x, y0 - y, color);
  438. }
  439. dx += 2;
  440. E += dx + 1;
  441. if (x != y) {
  442. tigrLine(bmp, x0 - y + 1, y0 + x, x0 + y, y0 + x, color);
  443. tigrLine(bmp, x0 - y + 1, y0 - x, x0 + y, y0 - x, color);
  444. }
  445. }
  446. }
  447. void tigrCircle(Tigr* bmp, int x0, int y0, int r, TPixel color) {
  448. int E = 1 - r;
  449. int dx = 0;
  450. int dy = -2 * r;
  451. int x = 0;
  452. int y = r;
  453. tigrPlot(bmp, x0, y0 + r, color);
  454. tigrPlot(bmp, x0, y0 - r, color);
  455. tigrPlot(bmp, x0 + r, y0, color);
  456. tigrPlot(bmp, x0 - r, y0, color);
  457. while (x < y - 1) {
  458. x++;
  459. if (E >= 0) {
  460. y--;
  461. dy += 2;
  462. E += dy;
  463. }
  464. dx += 2;
  465. E += dx + 1;
  466. tigrPlot(bmp, x0 + x, y0 + y, color);
  467. tigrPlot(bmp, x0 - x, y0 + y, color);
  468. tigrPlot(bmp, x0 + x, y0 - y, color);
  469. tigrPlot(bmp, x0 - x, y0 - y, color);
  470. if (x != y) {
  471. tigrPlot(bmp, x0 + y, y0 + x, color);
  472. tigrPlot(bmp, x0 - y, y0 + x, color);
  473. tigrPlot(bmp, x0 + y, y0 - x, color);
  474. tigrPlot(bmp, x0 - y, y0 - x, color);
  475. }
  476. }
  477. }
  478. TPixel tigrGet(Tigr* bmp, int x, int y) {
  479. TPixel empty = { 0, 0, 0, 0 };
  480. if (x >= 0 && y >= 0 && x < bmp->w && y < bmp->h)
  481. return bmp->pix[y * bmp->w + x];
  482. return empty;
  483. }
  484. void tigrPlot(Tigr* bmp, int x, int y, TPixel pix) {
  485. int xa, i, a;
  486. int cx = bmp->cx;
  487. int cy = bmp->cy;
  488. int cw = bmp->cw >= 0 ? bmp->cw : bmp->w;
  489. int ch = bmp->ch >= 0 ? bmp->ch : bmp->h;
  490. if (x >= cx && y >= cy && x < cx + cw && y < cy + ch) {
  491. xa = EXPAND(pix.a);
  492. a = xa * xa;
  493. i = y * bmp->w + x;
  494. bmp->pix[i].r += (unsigned char)((pix.r - bmp->pix[i].r) * a >> 16);
  495. bmp->pix[i].g += (unsigned char)((pix.g - bmp->pix[i].g) * a >> 16);
  496. bmp->pix[i].b += (unsigned char)((pix.b - bmp->pix[i].b) * a >> 16);
  497. bmp->pix[i].a += (bmp->blitMode) * (unsigned char)((pix.a - bmp->pix[i].a) * a >> 16);
  498. }
  499. }
  500. void tigrClip(Tigr* bmp, int cx, int cy, int cw, int ch) {
  501. bmp->cx = cx;
  502. bmp->cy = cy;
  503. bmp->cw = cw;
  504. bmp->ch = ch;
  505. }
  506. void tigrBlit(Tigr* dst, Tigr* src, int dx, int dy, int sx, int sy, int w, int h) {
  507. int cw = dst->cw >= 0 ? dst->cw : dst->w;
  508. int ch = dst->ch >= 0 ? dst->ch : dst->h;
  509. CLIP();
  510. TPixel* ts = &src->pix[sy * src->w + sx];
  511. TPixel* td = &dst->pix[dy * dst->w + dx];
  512. int st = src->w;
  513. int dt = dst->w;
  514. do {
  515. memcpy(td, ts, w * sizeof(TPixel));
  516. ts += st;
  517. td += dt;
  518. } while (--h);
  519. }
  520. void tigrBlitTint(Tigr* dst, Tigr* src, int dx, int dy, int sx, int sy, int w, int h, TPixel tint) {
  521. int cw = dst->cw >= 0 ? dst->cw : dst->w;
  522. int ch = dst->ch >= 0 ? dst->ch : dst->h;
  523. CLIP();
  524. int xr = EXPAND(tint.r);
  525. int xg = EXPAND(tint.g);
  526. int xb = EXPAND(tint.b);
  527. int xa = EXPAND(tint.a);
  528. TPixel* ts = &src->pix[sy * src->w + sx];
  529. TPixel* td = &dst->pix[dy * dst->w + dx];
  530. int st = src->w;
  531. int dt = dst->w;
  532. do {
  533. for (int x = 0; x < w; x++) {
  534. unsigned r = (xr * ts[x].r) >> 8;
  535. unsigned g = (xg * ts[x].g) >> 8;
  536. unsigned b = (xb * ts[x].b) >> 8;
  537. unsigned a = xa * EXPAND(ts[x].a);
  538. td[x].r += (unsigned char)((r - td[x].r) * a >> 16);
  539. td[x].g += (unsigned char)((g - td[x].g) * a >> 16);
  540. td[x].b += (unsigned char)((b - td[x].b) * a >> 16);
  541. td[x].a += (dst->blitMode) * (unsigned char)((ts[x].a - td[x].a) * a >> 16);
  542. }
  543. ts += st;
  544. td += dt;
  545. } while (--h);
  546. }
  547. void tigrBlitAlpha(Tigr* dst, Tigr* src, int dx, int dy, int sx, int sy, int w, int h, float alpha) {
  548. alpha = (alpha < 0) ? 0 : (alpha > 1 ? 1 : alpha);
  549. tigrBlitTint(dst, src, dx, dy, sx, sy, w, h, tigrRGBA(0xff, 0xff, 0xff, (unsigned char)(alpha * 255)));
  550. }
  551. void tigrBlitMode(Tigr* dst, int mode) {
  552. dst->blitMode = mode;
  553. }
  554. #undef CLIP0
  555. #undef CLIP1
  556. #undef CLIP
  557. //////// End of inlined file: tigr_bitmaps.c ////////
  558. //////// Start of inlined file: tigr_loadpng.c ////////
  559. //#include "tigr_internal.h"
  560. #include <stdlib.h>
  561. #include <string.h>
  562. #include <errno.h>
  563. typedef struct {
  564. const unsigned char *p, *end;
  565. } PNG;
  566. static unsigned get32(const unsigned char* v) {
  567. return (v[0] << 24) | (v[1] << 16) | (v[2] << 8) | v[3];
  568. }
  569. static const unsigned char* find(PNG* png, const char* chunk, unsigned minlen) {
  570. const unsigned char* start;
  571. while (png->p < png->end) {
  572. unsigned len = get32(png->p + 0);
  573. start = png->p;
  574. png->p += len + 12;
  575. if (memcmp(start + 4, chunk, 4) == 0 && len >= minlen && png->p <= png->end)
  576. return start + 8;
  577. }
  578. return NULL;
  579. }
  580. static unsigned char paeth(unsigned char a, unsigned char b, unsigned char c) {
  581. int p = a + b - c;
  582. int pa = abs(p - a), pb = abs(p - b), pc = abs(p - c);
  583. return (pa <= pb && pa <= pc) ? a : (pb <= pc) ? b : c;
  584. }
  585. static int rowBytes(int w, int bipp) {
  586. int rowBits = w * bipp;
  587. return rowBits / 8 + ((rowBits % 8) ? 1 : 0);
  588. }
  589. static int unfilter(int w, int h, int bipp, unsigned char* raw) {
  590. int len = rowBytes(w, bipp);
  591. int bpp = rowBytes(1, bipp);
  592. int x, y;
  593. unsigned char* first = (unsigned char*)malloc(len + 1);
  594. memset(first, 0, len + 1);
  595. unsigned char* prev = first;
  596. for (y = 0; y < h; y++, prev = raw, raw += len) {
  597. #define LOOP(A, B) \
  598. for (x = 0; x < bpp; x++) \
  599. raw[x] += A; \
  600. for (; x < len; x++) \
  601. raw[x] += B; \
  602. break
  603. switch (*raw++) {
  604. case 0:
  605. break;
  606. case 1:
  607. LOOP(0, raw[x - bpp]);
  608. case 2:
  609. LOOP(prev[x], prev[x]);
  610. case 3:
  611. LOOP(prev[x] / 2, (raw[x - bpp] + prev[x]) / 2);
  612. case 4:
  613. LOOP(prev[x], paeth(raw[x - bpp], prev[x], prev[x - bpp]));
  614. default:
  615. return 0;
  616. }
  617. #undef LOOP
  618. }
  619. free(first);
  620. return 1;
  621. }
  622. static void convert(int bypp, int w, int h, const unsigned char* src, TPixel* dest, const unsigned char* trns) {
  623. int x, y;
  624. for (y = 0; y < h; y++) {
  625. src++; // skip filter byte
  626. for (x = 0; x < w; x++, src += bypp) {
  627. switch (bypp) {
  628. case 1: {
  629. unsigned char c = src[0];
  630. if (trns && c == *trns) {
  631. *dest++ = tigrRGBA(c, c, c, 0);
  632. break;
  633. } else {
  634. *dest++ = tigrRGB(c, c, c);
  635. break;
  636. }
  637. }
  638. case 2:
  639. *dest++ = tigrRGBA(src[0], src[0], src[0], src[1]);
  640. break;
  641. case 3: {
  642. unsigned char r = src[0];
  643. unsigned char g = src[1];
  644. unsigned char b = src[2];
  645. if (trns && trns[1] == r && trns[3] == g && trns[5] == b) {
  646. *dest++ = tigrRGBA(r, g, b, 0);
  647. break;
  648. } else {
  649. *dest++ = tigrRGB(r, g, b);
  650. break;
  651. }
  652. }
  653. case 4:
  654. *dest++ = tigrRGBA(src[0], src[1], src[2], src[3]);
  655. break;
  656. }
  657. }
  658. }
  659. }
  660. static void depalette(int w,
  661. int h,
  662. unsigned char* src,
  663. TPixel* dest,
  664. int bipp,
  665. const unsigned char* plte,
  666. const unsigned char* trns,
  667. int trnsSize) {
  668. int x, y, c;
  669. unsigned char alpha;
  670. int mask = 0, len = 0;
  671. switch (bipp) {
  672. case 4:
  673. mask = 15;
  674. len = 1;
  675. break;
  676. case 2:
  677. mask = 3;
  678. len = 3;
  679. break;
  680. case 1:
  681. mask = 1;
  682. len = 7;
  683. }
  684. for (y = 0; y < h; y++) {
  685. src++; // skip filter byte
  686. for (x = 0; x < w; x++) {
  687. if (bipp == 8) {
  688. c = *src++;
  689. } else {
  690. int pos = x & len;
  691. c = (src[0] >> ((len - pos) * bipp)) & mask;
  692. if (pos == len) {
  693. src++;
  694. }
  695. }
  696. alpha = 255;
  697. if (c < trnsSize) {
  698. alpha = trns[c];
  699. }
  700. *dest++ = tigrRGBA(plte[c * 3 + 0], plte[c * 3 + 1], plte[c * 3 + 2], alpha);
  701. }
  702. }
  703. }
  704. #define FAIL() \
  705. { \
  706. errno = EINVAL; \
  707. goto err; \
  708. }
  709. #define CHECK(X) \
  710. if (!(X)) \
  711. FAIL()
  712. static int outsize(Tigr* bmp, int bipp) {
  713. return (rowBytes(bmp->w, bipp) + 1) * bmp->h;
  714. }
  715. static Tigr* tigrLoadPng(PNG* png) {
  716. const unsigned char *ihdr, *idat, *plte, *trns, *first;
  717. int trnsSize = 0;
  718. int depth, ctype, bipp;
  719. int datalen = 0;
  720. unsigned char *data = NULL, *out;
  721. Tigr* bmp = NULL;
  722. CHECK(memcmp(png->p, "\211PNG\r\n\032\n", 8) == 0); // PNG signature
  723. png->p += 8;
  724. first = png->p;
  725. // Read IHDR
  726. ihdr = find(png, "IHDR", 13);
  727. CHECK(ihdr);
  728. depth = ihdr[8];
  729. ctype = ihdr[9];
  730. switch (ctype) {
  731. case 0:
  732. bipp = depth;
  733. break; // greyscale
  734. case 2:
  735. bipp = 3 * depth;
  736. break; // RGB
  737. case 3:
  738. bipp = depth;
  739. break; // paletted
  740. case 4:
  741. bipp = 2 * depth;
  742. break; // grey+alpha
  743. case 6:
  744. bipp = 4 * depth;
  745. break; // RGBA
  746. default:
  747. FAIL();
  748. }
  749. // Allocate bitmap (+1 width to save room for stupid PNG filter bytes)
  750. bmp = tigrBitmap(get32(ihdr + 0) + 1, get32(ihdr + 4));
  751. CHECK(bmp);
  752. bmp->w--;
  753. // We support 8-bit color components and 1, 2, 4 and 8 bit palette formats.
  754. // No interlacing, or wacky filter types.
  755. CHECK((depth != 16) && ihdr[10] == 0 && ihdr[11] == 0 && ihdr[12] == 0);
  756. // Join IDAT chunks.
  757. for (idat = find(png, "IDAT", 0); idat; idat = find(png, "IDAT", 0)) {
  758. unsigned len = get32(idat - 8);
  759. data = (unsigned char*)realloc(data, datalen + len);
  760. if (!data)
  761. break;
  762. memcpy(data + datalen, idat, len);
  763. datalen += len;
  764. }
  765. // Find palette.
  766. png->p = first;
  767. plte = find(png, "PLTE", 0);
  768. // Find transparency info.
  769. png->p = first;
  770. trns = find(png, "tRNS", 0);
  771. if (trns) {
  772. trnsSize = get32(trns - 8);
  773. }
  774. CHECK(data && datalen >= 6);
  775. CHECK((data[0] & 0x0f) == 0x08 // compression method (RFC 1950)
  776. && (data[0] & 0xf0) <= 0x70 // window size
  777. && (data[1] & 0x20) == 0); // preset dictionary present
  778. out = (unsigned char*)bmp->pix + outsize(bmp, 32) - outsize(bmp, bipp);
  779. CHECK(tigrInflate(out, outsize(bmp, bipp), data + 2, datalen - 6));
  780. CHECK(unfilter(bmp->w, bmp->h, bipp, out));
  781. if (ctype == 3) {
  782. CHECK(plte);
  783. depalette(bmp->w, bmp->h, out, bmp->pix, bipp, plte, trns, trnsSize);
  784. } else {
  785. CHECK(bipp % 8 == 0);
  786. convert(bipp / 8, bmp->w, bmp->h, out, bmp->pix, trns);
  787. }
  788. free(data);
  789. return bmp;
  790. err:
  791. if (data)
  792. free(data);
  793. if (bmp)
  794. tigrFree(bmp);
  795. return NULL;
  796. }
  797. #undef CHECK
  798. #undef FAIL
  799. Tigr* tigrLoadImageMem(const void* data, int length) {
  800. PNG png;
  801. png.p = (unsigned char*)data;
  802. png.end = (unsigned char*)data + length;
  803. return tigrLoadPng(&png);
  804. }
  805. Tigr* tigrLoadImage(const char* fileName) {
  806. int len;
  807. void* data;
  808. Tigr* bmp;
  809. data = tigrReadFile(fileName, &len);
  810. if (!data)
  811. return NULL;
  812. bmp = tigrLoadImageMem(data, len);
  813. free(data);
  814. return bmp;
  815. }
  816. //////// End of inlined file: tigr_loadpng.c ////////
  817. //////// Start of inlined file: tigr_savepng.c ////////
  818. //#include "tigr_internal.h"
  819. #include <stdio.h>
  820. #include <stdlib.h>
  821. #include <string.h>
  822. #include <errno.h>
  823. typedef struct {
  824. unsigned crc, adler, bits, prev, runlen;
  825. FILE* out;
  826. unsigned crcTable[256];
  827. } Save;
  828. static const unsigned crctable[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4,
  829. 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
  830. 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
  831. static void put(Save* s, unsigned v) {
  832. fputc(v, s->out);
  833. s->crc = (s->crc >> 4) ^ crctable[(s->crc & 15) ^ (v & 15)];
  834. s->crc = (s->crc >> 4) ^ crctable[(s->crc & 15) ^ (v >> 4)];
  835. }
  836. static void updateAdler(Save* s, unsigned v) {
  837. unsigned s1 = s->adler & 0xffff, s2 = (s->adler >> 16) & 0xffff;
  838. s1 = (s1 + v) % 65521;
  839. s2 = (s2 + s1) % 65521;
  840. s->adler = (s2 << 16) + s1;
  841. }
  842. static void put32(Save* s, unsigned v) {
  843. put(s, (v >> 24) & 0xff);
  844. put(s, (v >> 16) & 0xff);
  845. put(s, (v >> 8) & 0xff);
  846. put(s, v & 0xff);
  847. }
  848. void putbits(Save* s, unsigned data, unsigned bitcount) {
  849. while (bitcount--) {
  850. unsigned prev = s->bits;
  851. s->bits = (s->bits >> 1) | ((data & 1) << 7);
  852. data >>= 1;
  853. if (prev & 1) {
  854. put(s, s->bits);
  855. s->bits = 0x80;
  856. }
  857. }
  858. }
  859. void putbitsr(Save* s, unsigned data, unsigned bitcount) {
  860. while (bitcount--)
  861. putbits(s, data >> bitcount, 1);
  862. }
  863. static void begin(Save* s, const char* id, unsigned len) {
  864. put32(s, len);
  865. s->crc = 0xffffffff;
  866. put(s, id[0]);
  867. put(s, id[1]);
  868. put(s, id[2]);
  869. put(s, id[3]);
  870. }
  871. static void literal(Save* s, unsigned v) {
  872. // Encode a literal/length using the built-in tables.
  873. // Could do better with a custom table but whatever.
  874. if (v < 144)
  875. putbitsr(s, 0x030 + v - 0, 8);
  876. else if (v < 256)
  877. putbitsr(s, 0x190 + v - 144, 9);
  878. else if (v < 280)
  879. putbitsr(s, 0x000 + v - 256, 7);
  880. else
  881. putbitsr(s, 0x0c0 + v - 280, 8);
  882. }
  883. static void encodelen(Save* s, unsigned code, unsigned bits, unsigned len) {
  884. literal(s, code + (len >> bits));
  885. putbits(s, len, bits);
  886. putbits(s, 0, 5);
  887. }
  888. static void endrun(Save* s) {
  889. s->runlen--;
  890. literal(s, s->prev);
  891. if (s->runlen >= 67)
  892. encodelen(s, 277, 4, s->runlen - 67);
  893. else if (s->runlen >= 35)
  894. encodelen(s, 273, 3, s->runlen - 35);
  895. else if (s->runlen >= 19)
  896. encodelen(s, 269, 2, s->runlen - 19);
  897. else if (s->runlen >= 11)
  898. encodelen(s, 265, 1, s->runlen - 11);
  899. else if (s->runlen >= 3)
  900. encodelen(s, 257, 0, s->runlen - 3);
  901. else
  902. while (s->runlen--)
  903. literal(s, s->prev);
  904. }
  905. static void encodeByte(Save* s, unsigned char v) {
  906. updateAdler(s, v);
  907. // Simple RLE compression. We could do better by doing a search
  908. // to find matches, but this works pretty well TBH.
  909. if (s->prev == v && s->runlen < 115) {
  910. s->runlen++;
  911. } else {
  912. if (s->runlen)
  913. endrun(s);
  914. s->prev = v;
  915. s->runlen = 1;
  916. }
  917. }
  918. static void savePngHeader(Save* s, Tigr* bmp) {
  919. fwrite("\211PNG\r\n\032\n", 8, 1, s->out);
  920. begin(s, "IHDR", 13);
  921. put32(s, bmp->w);
  922. put32(s, bmp->h);
  923. put(s, 8); // bit depth
  924. put(s, 6); // RGBA
  925. put(s, 0); // compression (deflate)
  926. put(s, 0); // filter (standard)
  927. put(s, 0); // interlace off
  928. put32(s, ~s->crc);
  929. }
  930. static long savePngData(Save* s, Tigr* bmp, long dataPos) {
  931. int x, y;
  932. long dataSize;
  933. begin(s, "IDAT", 0);
  934. put(s, 0x08); // zlib compression method
  935. put(s, 0x1d); // zlib compression flags
  936. putbits(s, 3, 3); // zlib last block + fixed dictionary
  937. for (y = 0; y < bmp->h; y++) {
  938. TPixel* row = &bmp->pix[y * bmp->w];
  939. TPixel prev = tigrRGBA(0, 0, 0, 0);
  940. encodeByte(s, 1); // sub filter
  941. for (x = 0; x < bmp->w; x++) {
  942. encodeByte(s, row[x].r - prev.r);
  943. encodeByte(s, row[x].g - prev.g);
  944. encodeByte(s, row[x].b - prev.b);
  945. encodeByte(s, row[x].a - prev.a);
  946. prev = row[x];
  947. }
  948. }
  949. endrun(s);
  950. literal(s, 256); // terminator
  951. while (s->bits != 0x80)
  952. putbits(s, 0, 1);
  953. put32(s, s->adler);
  954. dataSize = (ftell(s->out) - dataPos) - 8;
  955. put32(s, ~s->crc);
  956. return dataSize;
  957. }
  958. int tigrSaveImage(const char* fileName, Tigr* bmp) {
  959. Save s;
  960. long dataPos, dataSize, err;
  961. // TODO - unicode?
  962. FILE* out = fopen(fileName, "wb");
  963. if (!out)
  964. return 1;
  965. s.out = out;
  966. s.adler = 1;
  967. s.bits = 0x80;
  968. s.prev = 0xffff;
  969. s.runlen = 0;
  970. savePngHeader(&s, bmp);
  971. dataPos = ftell(s.out);
  972. dataSize = savePngData(&s, bmp, dataPos);
  973. // End chunk.
  974. begin(&s, "IEND", 0);
  975. put32(&s, ~s.crc);
  976. // Write back payload size.
  977. fseek(out, dataPos, SEEK_SET);
  978. put32(&s, dataSize);
  979. err = ferror(out);
  980. fclose(out);
  981. return !err;
  982. }
  983. //////// End of inlined file: tigr_savepng.c ////////
  984. //////// Start of inlined file: tigr_inflate.c ////////
  985. //#include "tigr_internal.h"
  986. #include <stdlib.h>
  987. #include <setjmp.h>
  988. typedef struct {
  989. unsigned bits, count;
  990. const unsigned char *in, *inend;
  991. unsigned char *out, *outend;
  992. jmp_buf jmp;
  993. unsigned litcodes[288], distcodes[32], lencodes[19];
  994. int tlit, tdist, tlen;
  995. } State;
  996. #define FAIL() longjmp(s->jmp, 1)
  997. #define CHECK(X) \
  998. if (!(X)) \
  999. FAIL()
  1000. // Built-in DEFLATE standard tables.
  1001. static char order[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
  1002. static char lenBits[29 + 2] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
  1003. 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 };
  1004. static int lenBase[29 + 2] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
  1005. 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 };
  1006. static char distBits[30 + 2] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
  1007. 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 0, 0 };
  1008. static int distBase[30 + 2] = {
  1009. 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129,
  1010. 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577
  1011. };
  1012. // Table to bit-reverse a byte.
  1013. static const unsigned char reverseTable[256] = {
  1014. #define R2(n) n, n + 128, n + 64, n + 192
  1015. #define R4(n) R2(n), R2(n + 32), R2(n + 16), R2(n + 48)
  1016. #define R6(n) R4(n), R4(n + 8), R4(n + 4), R4(n + 12)
  1017. R6(0), R6(2), R6(1), R6(3)
  1018. };
  1019. static unsigned rev16(unsigned n) {
  1020. return (reverseTable[n & 0xff] << 8) | reverseTable[(n >> 8) & 0xff];
  1021. }
  1022. static int bits(State* s, int n) {
  1023. int v = s->bits & ((1 << n) - 1);
  1024. s->bits >>= n;
  1025. s->count -= n;
  1026. while (s->count < 16) {
  1027. CHECK(s->in != s->inend);
  1028. s->bits |= (*s->in++) << s->count;
  1029. s->count += 8;
  1030. }
  1031. return v;
  1032. }
  1033. static unsigned char* emit(State* s, int len) {
  1034. s->out += len;
  1035. CHECK(s->out <= s->outend);
  1036. return s->out - len;
  1037. }
  1038. static void copy(State* s, const unsigned char* src, int len) {
  1039. unsigned char* dest = emit(s, len);
  1040. while (len--)
  1041. *dest++ = *src++;
  1042. }
  1043. static int build(State* s, unsigned* tree, unsigned char* lens, unsigned int symcount) {
  1044. unsigned int codes[16], first[16], counts[16] = { 0 };
  1045. // Frequency count.
  1046. for (unsigned int n = 0; n < symcount; n++)
  1047. counts[lens[n]]++;
  1048. // Distribute codes.
  1049. counts[0] = codes[0] = first[0] = 0;
  1050. for (unsigned int n = 1; n <= 15; n++) {
  1051. codes[n] = (codes[n - 1] + counts[n - 1]) << 1;
  1052. first[n] = first[n - 1] + counts[n - 1];
  1053. }
  1054. CHECK(first[15] + counts[15] <= symcount);
  1055. // Insert keys into the tree for each symbol.
  1056. for (unsigned int n = 0; n < symcount; n++) {
  1057. int len = lens[n];
  1058. if (len != 0) {
  1059. unsigned code = codes[len]++, slot = first[len]++;
  1060. tree[slot] = (code << (32 - len)) | (n << 4) | len;
  1061. }
  1062. }
  1063. return first[15];
  1064. }
  1065. static int decode(State* s, unsigned tree[], int max) {
  1066. // Find the next prefix code.
  1067. unsigned lo = 0, hi = max, key;
  1068. unsigned search = (rev16(s->bits) << 16) | 0xffff;
  1069. while (lo < hi) {
  1070. unsigned guess = (lo + hi) / 2;
  1071. if (search < tree[guess])
  1072. hi = guess;
  1073. else
  1074. lo = guess + 1;
  1075. }
  1076. // Pull out the key and check it.
  1077. key = tree[lo - 1];
  1078. CHECK(((search ^ key) >> (32 - (key & 0xf))) == 0);
  1079. bits(s, key & 0xf);
  1080. return (key >> 4) & 0xfff;
  1081. }
  1082. static void run(State* s, int sym) {
  1083. int length = bits(s, lenBits[sym]) + lenBase[sym];
  1084. int dsym = decode(s, s->distcodes, s->tdist);
  1085. int offs = bits(s, distBits[dsym]) + distBase[dsym];
  1086. copy(s, s->out - offs, length);
  1087. }
  1088. static void block(State* s) {
  1089. for (;;) {
  1090. int sym = decode(s, s->litcodes, s->tlit);
  1091. if (sym < 256)
  1092. *emit(s, 1) = (unsigned char)sym;
  1093. else if (sym > 256)
  1094. run(s, sym - 257);
  1095. else
  1096. break;
  1097. }
  1098. }
  1099. static void stored(State* s) {
  1100. // Uncompressed data block.
  1101. int len;
  1102. bits(s, s->count & 7);
  1103. len = bits(s, 16);
  1104. CHECK(((len ^ s->bits) & 0xffff) == 0xffff);
  1105. CHECK(s->in + len <= s->inend);
  1106. copy(s, s->in, len);
  1107. s->in += len;
  1108. bits(s, 16);
  1109. }
  1110. static void fixed(State* s) {
  1111. // Fixed set of Huffman codes.
  1112. int n;
  1113. unsigned char lens[288 + 32];
  1114. for (n = 0; n <= 143; n++)
  1115. lens[n] = 8;
  1116. for (n = 144; n <= 255; n++)
  1117. lens[n] = 9;
  1118. for (n = 256; n <= 279; n++)
  1119. lens[n] = 7;
  1120. for (n = 280; n <= 287; n++)
  1121. lens[n] = 8;
  1122. for (n = 0; n < 32; n++)
  1123. lens[288 + n] = 5;
  1124. // Build lit/dist trees.
  1125. s->tlit = build(s, s->litcodes, lens, 288);
  1126. s->tdist = build(s, s->distcodes, lens + 288, 32);
  1127. }
  1128. static void dynamic(State* s) {
  1129. int n, i, nlit, ndist, nlen;
  1130. unsigned char lenlens[19] = { 0 }, lens[288 + 32];
  1131. nlit = 257 + bits(s, 5);
  1132. ndist = 1 + bits(s, 5);
  1133. nlen = 4 + bits(s, 4);
  1134. for (n = 0; n < nlen; n++)
  1135. lenlens[(int) order[n]] = (unsigned char)bits(s, 3);
  1136. // Build the tree for decoding code lengths.
  1137. s->tlen = build(s, s->lencodes, lenlens, 19);
  1138. // Decode code lengths.
  1139. for (n = 0; n < nlit + ndist;) {
  1140. int sym = decode(s, s->lencodes, s->tlen);
  1141. switch (sym) {
  1142. case 16:
  1143. for (i = 3 + bits(s, 2); i; i--, n++)
  1144. lens[n] = lens[n - 1];
  1145. break;
  1146. case 17:
  1147. for (i = 3 + bits(s, 3); i; i--, n++)
  1148. lens[n] = 0;
  1149. break;
  1150. case 18:
  1151. for (i = 11 + bits(s, 7); i; i--, n++)
  1152. lens[n] = 0;
  1153. break;
  1154. default:
  1155. lens[n++] = (unsigned char)sym;
  1156. break;
  1157. }
  1158. }
  1159. // Build lit/dist trees.
  1160. s->tlit = build(s, s->litcodes, lens, nlit);
  1161. s->tdist = build(s, s->distcodes, lens + nlit, ndist);
  1162. }
  1163. int tigrInflate(void* out, unsigned outlen, const void* in, unsigned inlen) {
  1164. int last;
  1165. State* s = (State*)calloc(1, sizeof(State));
  1166. // We assume we can buffer 2 extra bytes from off the end of 'in'.
  1167. s->in = (unsigned char*)in;
  1168. s->inend = s->in + inlen + 2;
  1169. s->out = (unsigned char*)out;
  1170. s->outend = s->out + outlen;
  1171. s->bits = 0;
  1172. s->count = 0;
  1173. bits(s, 0);
  1174. if (setjmp(s->jmp) == 1) {
  1175. free(s);
  1176. return 0;
  1177. }
  1178. do {
  1179. last = bits(s, 1);
  1180. switch (bits(s, 2)) {
  1181. case 0:
  1182. stored(s);
  1183. break;
  1184. case 1:
  1185. fixed(s);
  1186. block(s);
  1187. break;
  1188. case 2:
  1189. dynamic(s);
  1190. block(s);
  1191. break;
  1192. case 3:
  1193. FAIL();
  1194. }
  1195. } while (!last);
  1196. free(s);
  1197. return 1;
  1198. }
  1199. #undef CHECK
  1200. #undef FAIL
  1201. //////// End of inlined file: tigr_inflate.c ////////
  1202. //////// Start of inlined file: tigr_print.c ////////
  1203. //#include "tigr_internal.h"
  1204. //////// Start of inlined file: tigr_font.h ////////
  1205. // Auto-generated by incbin.pl from font.png
  1206. const unsigned char tigr_font[] = {
  1207. 0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52,
  1208. 0x00,0x00,0x00,0xfd,0x00,0x00,0x00,0x5c,0x08,0x03,0x00,0x00,0x00,0x92,0xab,0x43,
  1209. 0x85,0x00,0x00,0x03,0x00,0x50,0x4c,0x54,0x45,0x5f,0x53,0x87,0x00,0x00,0x00,0x54,
  1210. 0x54,0x54,0xff,0xff,0xfa,0x31,0x2a,0x42,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1211. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1212. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1213. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1214. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1215. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1216. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1217. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1218. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1219. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1220. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1221. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1222. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1223. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1224. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1225. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1226. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1227. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1228. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1229. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1230. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1231. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1232. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1233. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1234. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1235. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1236. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1237. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1238. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1239. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1240. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1241. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1242. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1243. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1244. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1245. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1246. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1247. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1248. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1249. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1250. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1251. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1252. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1253. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1254. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,
  1255. 0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,
  1256. 0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,
  1257. 0x80,0x00,0x00,0x80,0x00,0x00,0x80,0x00,0x00,0x4a,0x44,0xb7,0x5a,0x00,0x00,0x00,
  1258. 0x01,0x74,0x52,0x4e,0x53,0x00,0x40,0xe6,0xd8,0x66,0x00,0x00,0x00,0x01,0x62,0x4b,
  1259. 0x47,0x44,0x00,0x88,0x05,0x1d,0x48,0x00,0x00,0x00,0x09,0x70,0x48,0x59,0x73,0x00,
  1260. 0x00,0x0b,0x13,0x00,0x00,0x0b,0x13,0x01,0x00,0x9a,0x9c,0x18,0x00,0x00,0x00,0x07,
  1261. 0x74,0x49,0x4d,0x45,0x07,0xe5,0x04,0x1c,0x16,0x0f,0x2b,0x56,0x9d,0x54,0x3b,0x00,
  1262. 0x00,0x0b,0x7c,0x49,0x44,0x41,0x54,0x78,0xda,0xed,0x5c,0x89,0x9a,0xec,0xac,0x0a,
  1263. 0x04,0xf5,0xfd,0x9f,0xf9,0x4e,0x94,0xa5,0x40,0x93,0x98,0xee,0x3e,0x73,0xe7,0xfb,
  1264. 0x67,0xce,0xd2,0x66,0x31,0x6a,0x29,0x51,0x4a,0x20,0xd4,0x7e,0xf3,0x1f,0x6a,0x34,
  1265. 0xfe,0xb4,0x5a,0xf9,0xf8,0x7f,0x24,0x54,0xf9,0xf8,0xf7,0x75,0xeb,0xeb,0x97,0xe0,
  1266. 0xd4,0x73,0x92,0x64,0xd7,0xab,0x90,0xa4,0xc3,0x91,0x59,0xb2,0x56,0x29,0x50,0xce,
  1267. 0xed,0xfa,0x71,0x74,0x94,0xd7,0x2f,0xd8,0xf5,0x7c,0x0e,0xf9,0xb1,0x74,0x69,0x15,
  1268. 0x13,0x14,0xfd,0x09,0xf4,0xd2,0x08,0x3e,0xfe,0xf6,0x53,0x86,0x9c,0xa5,0x8d,0xcc,
  1269. 0xd2,0x45,0x9a,0x2c,0xd0,0x7f,0x65,0x63,0x45,0xc1,0xa3,0x00,0xae,0x78,0x7d,0xb4,
  1270. 0xb9,0x9f,0xf3,0x57,0xb9,0x7a,0xfd,0x38,0xc3,0x7c,0x90,0x36,0xad,0xba,0x68,0x75,
  1271. 0x1c,0x8a,0x7e,0x05,0x3d,0x1f,0xcf,0xfa,0x18,0x0c,0xd8,0xad,0xff,0x96,0x9e,0xa3,
  1272. 0xd7,0xc0,0x36,0xec,0x90,0xe9,0x0c,0x7d,0x1d,0x68,0x6c,0x6c,0x7b,0x01,0x5f,0xa5,
  1273. 0x0d,0x74,0x23,0x25,0xe9,0xf5,0xd1,0xbb,0xbd,0x22,0x62,0xc1,0xa5,0xd7,0x53,0x2a,
  1274. 0x02,0x38,0x9a,0x35,0x04,0xa4,0x8f,0x90,0x16,0xf9,0x0a,0x7a,0xfa,0x7a,0xb6,0x8f,
  1275. 0xe9,0xd1,0x09,0x63,0x6c,0x8f,0x46,0x70,0xd1,0x7e,0x1d,0x08,0x07,0x20,0x41,0xdf,
  1276. 0x81,0x15,0x6b,0x03,0x11,0x1e,0xf6,0x3e,0xb1,0xde,0xec,0xc3,0x22,0x12,0x31,0x46,
  1277. 0x4d,0x9f,0xfd,0xaa,0x41,0x7b,0x5d,0xf3,0xb3,0xe7,0xe3,0x5a,0x3d,0x1d,0xbd,0xd6,
  1278. 0xff,0x1f,0xe0,0xa9,0x4b,0x48,0x2f,0x6c,0x0c,0xc2,0x78,0xe4,0x25,0xf4,0x32,0x6a,
  1279. 0x2a,0xf9,0xac,0xaf,0xeb,0xa8,0xa6,0x8e,0x54,0x87,0x27,0x8c,0xfd,0xd1,0x5f,0x63,
  1280. 0xb8,0xbc,0x39,0xe4,0xa3,0x63,0x12,0x2e,0x6f,0x49,0xbf,0xfe,0xd5,0x60,0xc6,0xf7,
  1281. 0x3d,0x4b,0xba,0xe6,0xb3,0x73,0xd6,0xeb,0xa3,0x11,0x2a,0xec,0x15,0x5f,0x83,0xf1,
  1282. 0xc8,0x53,0xf4,0xec,0xaf,0x50,0x92,0xfc,0xa3,0xdc,0x31,0x24,0x7a,0x8e,0xe8,0x0f,
  1283. 0xc1,0x18,0xd5,0xae,0x24,0x5f,0x85,0xa6,0x04,0xf4,0xde,0x8d,0x84,0xa8,0xb3,0xa4,
  1284. 0x6b,0x3e,0x3b,0xf7,0xfb,0x0d,0x85,0x7d,0x74,0xb6,0x74,0xe8,0xa8,0xe2,0x8d,0xb1,
  1285. 0x07,0xc9,0xaf,0xa3,0xdc,0xca,0x3a,0x24,0x32,0xa8,0x8e,0x9e,0x48,0x90,0x68,0x43,
  1286. 0x1b,0x4e,0xa3,0xa9,0xf5,0x36,0xeb,0x15,0x5a,0xa3,0xca,0x69,0xc8,0x37,0xbd,0xf7,
  1287. 0x2a,0xec,0x63,0xce,0x97,0x66,0xf4,0xf4,0x33,0x92,0xdf,0xfb,0x13,0x3b,0x43,0xc6,
  1288. 0x9e,0x6d,0xe2,0x8f,0x2b,0xde,0x84,0x5e,0x32,0xfb,0xdc,0x80,0x92,0x2e,0xd7,0x4d,
  1289. 0x06,0xf0,0xfd,0x96,0xc9,0x05,0x9f,0xb7,0x74,0xcc,0x4d,0xc7,0x73,0x30,0xe7,0x17,
  1290. 0xa2,0xd7,0xc7,0x1e,0x24,0x7f,0x4c,0x7e,0x36,0x9e,0x76,0x7a,0x48,0x98,0xbe,0xd0,
  1291. 0x32,0xf3,0xe4,0xf5,0x1e,0x06,0xa3,0xe7,0x28,0x92,0xb9,0x67,0x65,0x11,0x52,0x4d,
  1292. 0xf5,0xfa,0x91,0x3d,0x9c,0x5b,0xfe,0x42,0xf8,0x3c,0xe4,0x6f,0xd6,0xf1,0xa1,0x01,
  1293. 0x2f,0xa3,0xcf,0x05,0x9d,0x9d,0x7a,0xce,0x36,0x67,0x6a,0x51,0x1a,0xda,0x69,0x01,
  1294. 0xef,0xa6,0xcd,0x3a,0x3e,0xa3,0x7f,0x4d,0xf2,0x3f,0x83,0x3e,0x4a,0xc3,0x3f,0x44,
  1295. 0x9f,0x4b,0x4f,0x55,0xfd,0x7f,0xd0,0xaf,0x0e,0x7f,0x32,0xfa,0xdf,0xce,0x72,0x54,
  1296. 0x01,0xa5,0xac,0x6a,0xa5,0xf3,0x3c,0x65,0xfb,0x7d,0x5d,0x88,0xe0,0x7a,0x5a,0xc0,
  1297. 0x74,0xe1,0xca,0xeb,0xf9,0x65,0x85,0x34,0x55,0x3c,0xad,0x7c,0x34,0x1f,0x60,0x53,
  1298. 0xaa,0x2f,0x3c,0x35,0x90,0x92,0x21,0x20,0x63,0x3d,0x63,0xd5,0x66,0xce,0x48,0x05,
  1299. 0x67,0x12,0x82,0x64,0x44,0xab,0x64,0xd3,0x8c,0xd9,0x16,0xac,0x88,0xde,0xf5,0xfd,
  1300. 0xdb,0x8a,0x30,0xd5,0x82,0xf7,0xd1,0x83,0xd6,0x58,0x7c,0xd9,0xe5,0x26,0x7a,0x9b,
  1301. 0xa3,0xef,0x7a,0x98,0x6a,0x33,0x53,0xe1,0xbc,0x44,0x11,0xc9,0x48,0x56,0x66,0xc6,
  1302. 0xea,0x4d,0xc2,0x18,0x0b,0xa2,0x8f,0xc2,0xb3,0xaa,0x30,0x8d,0xa0,0xe8,0xcc,0xa6,
  1303. 0x25,0xad,0xd1,0x33,0x56,0x55,0x55,0xdd,0x57,0x32,0xc6,0xa6,0x60,0x1e,0x60,0x61,
  1304. 0x4d,0x6e,0x83,0xbf,0xaa,0x2e,0x07,0x8d,0x0b,0xad,0x76,0x71,0x52,0xc5,0x9a,0x43,
  1305. 0x2f,0x98,0xa6,0x9d,0xd0,0x9b,0x9a,0xae,0xe5,0xd8,0x98,0xdf,0xa0,0x77,0xed,0x86,
  1306. 0x61,0x11,0x3f,0x45,0x4f,0x2c,0x55,0xb9,0xfe,0xe4,0x10,0x1a,0x39,0xfa,0x63,0x35,
  1307. 0xf4,0x35,0x59,0xd0,0x93,0x6b,0xb2,0x31,0x4d,0xe8,0x59,0x15,0x57,0x4d,0xeb,0x44,
  1308. 0x4a,0xa6,0xb1,0x0f,0xe8,0x95,0xcb,0xc5,0x57,0x06,0xbb,0x3b,0x14,0xc8,0x71,0x57,
  1309. 0x64,0x81,0xde,0xe9,0x93,0xd0,0x4f,0xe1,0x4f,0xd0,0xf1,0x42,0x07,0x08,0x95,0x59,
  1310. 0x40,0xdf,0xe5,0xe6,0xec,0xb5,0x4a,0x95,0x26,0xc9,0x0f,0x20,0x16,0xe8,0xf9,0x72,
  1311. 0xd6,0x43,0xb4,0xda,0xd6,0x58,0x20,0xd7,0xc4,0x0f,0x16,0x73,0x9b,0x6f,0x10,0x60,
  1312. 0x3f,0x39,0xc3,0x10,0x9a,0xbd,0x46,0xcf,0x75,0x28,0xb0,0xb4,0xf1,0x1a,0xce,0xef,
  1313. 0xfd,0x0a,0x3d,0x8e,0xf9,0x2e,0x7a,0x7b,0x35,0x72,0xaf,0xac,0xd0,0x03,0x6f,0xb0,
  1314. 0x07,0x0a,0x9f,0xf1,0x28,0x25,0x43,0x4b,0xf4,0xc4,0x75,0xb5,0x72,0x05,0xb2,0x91,
  1315. 0x49,0x4a,0x24,0x1f,0x79,0x99,0x61,0x10,0xbb,0x3c,0xc9,0xc5,0x99,0xf9,0x84,0xcd,
  1316. 0xe4,0xfb,0x8a,0xc9,0xce,0xd9,0x2a,0x28,0x1c,0x27,0x00,0x1f,0x7b,0x5f,0xf1,0x74,
  1317. 0x7b,0x0d,0x09,0x58,0x3f,0x6b,0x43,0x33,0x76,0x52,0x61,0x24,0xa4,0x24,0x72,0x12,
  1318. 0x48,0x4a,0x24,0x1f,0xe1,0x39,0x21,0x2b,0x85,0xe6,0xeb,0xfd,0xaa,0x1e,0x20,0xab,
  1319. 0xc1,0x02,0x75,0xc7,0x2b,0xb2,0x20,0x16,0xba,0x15,0xcf,0x43,0x81,0xb2,0x17,0xc6,
  1320. 0xbe,0xdf,0x33,0xaa,0x2e,0x42,0x05,0x19,0x68,0x9c,0xdc,0x75,0x4d,0xf7,0xdf,0x28,
  1321. 0xa4,0xab,0xf4,0x3a,0x83,0xb7,0xf1,0x79,0x81,0xeb,0x1c,0x8d,0xce,0xd4,0xf2,0x9f,
  1322. 0x87,0xfe,0x9d,0x02,0xff,0xd0,0x3f,0x44,0xff,0xbb,0x59,0x8e,0x4f,0x85,0xbe,0x96,
  1323. 0x41,0x17,0xe1,0x6d,0x51,0x1f,0x73,0x6e,0x53,0x2d,0xe3,0xe2,0xf6,0xea,0x58,0x37,
  1324. 0x57,0x1b,0x9e,0x88,0x4e,0x0b,0x3b,0x9e,0x78,0xf7,0x53,0xe8,0x6b,0xc5,0x49,0xc9,
  1325. 0x16,0x2a,0x99,0x57,0x93,0xc2,0xf4,0xed,0xe8,0x75,0xb5,0x6c,0x1c,0x87,0xec,0x12,
  1326. 0x7d,0xdf,0xb5,0x5d,0x51,0x4b,0xa3,0xaa,0xf1,0x36,0x30,0x58,0xd3,0x13,0x60,0xec,
  1327. 0x51,0xbf,0x36,0xb5,0xe7,0x82,0xc1,0x42,0x41,0x14,0xaa,0xb9,0x64,0x74,0xb3,0xa2,
  1328. 0xdc,0xc8,0x1b,0xe3,0x64,0xf6,0x0e,0x7d,0x57,0x1b,0x16,0x06,0xb3,0x48,0x61,0x59,
  1329. 0xfb,0x74,0x71,0x39,0xa0,0x07,0xfd,0x1a,0x38,0x1d,0xef,0x33,0x5a,0xac,0x66,0x0f,
  1330. 0x3d,0xb0,0x59,0x35,0x49,0xd5,0x3a,0xec,0x6f,0x9d,0xd6,0xdd,0xec,0x6c,0x99,0x89,
  1331. 0x28,0xaa,0x9e,0xab,0x6d,0x8b,0x13,0xb2,0x01,0xe8,0x5d,0xbf,0x46,0x4e,0x77,0xab,
  1332. 0x42,0x33,0x58,0xce,0xee,0xf9,0x6c,0xa2,0xb3,0x66,0x53,0x85,0xb1,0x2f,0x9d,0xcc,
  1333. 0x1e,0xdb,0xca,0x77,0xe8,0x67,0xd2,0xc5,0x99,0xdc,0x5d,0x37,0x2b,0x8c,0x3d,0xa0,
  1334. 0x37,0x4e,0xb7,0x45,0x20,0xd4,0x72,0x76,0xc7,0xe8,0x92,0x66,0x4e,0xc6,0xeb,0xa2,
  1335. 0xe4,0x93,0x6c,0xcb,0x6f,0xa0,0xa7,0x6b,0xf4,0xb4,0x3b,0xf6,0x4e,0x70,0xae,0x59,
  1336. 0xcd,0x92,0xe5,0x98,0xa1,0xfb,0x84,0xd3,0x4c,0x2f,0x12,0x98,0x7c,0x56,0xe8,0xef,
  1337. 0xdf,0xfb,0x28,0xf9,0xc8,0x6f,0xdc,0x66,0xaa,0xec,0x02,0xc8,0xc6,0x29,0x7a,0x9b,
  1338. 0x21,0xae,0x58,0x4d,0xb4,0xc9,0x22,0xcb,0x11,0x12,0x83,0xb5,0xb2,0xed,0x5c,0xf0,
  1339. 0x4c,0x82,0x60,0xd6,0x43,0xdb,0x7e,0x79,0x80,0x9e,0xd0,0xc8,0x62,0xfc,0xc6,0x2e,
  1340. 0x83,0x2d,0xa5,0x2c,0xc8,0x88,0xac,0x78,0x89,0x9f,0x5c,0xb0,0x1a,0xe5,0xf3,0x58,
  1341. 0x90,0x36,0x43,0x48,0xcc,0x9a,0xe3,0x94,0xc0,0xaa,0xfc,0x71,0x36,0x86,0xd3,0x92,
  1342. 0x8d,0x69,0x0b,0xfd,0xf6,0x46,0x7e,0x36,0x3e,0x92,0x5b,0xb4,0xd3,0xa5,0x8b,0x05,
  1343. 0x1a,0xd5,0x8a,0xfc,0xd4,0x5d,0xed,0xa9,0x98,0x4c,0xda,0x5b,0xae,0xfd,0xe3,0xe8,
  1344. 0xd1,0xf8,0xe8,0xa6,0xf4,0x7c,0xe9,0xdf,0xa3,0x8f,0xed,0xf8,0x2e,0xf4,0x68,0x7c,
  1345. 0xb4,0x0a,0xa7,0x4b,0x17,0xe8,0x4d,0xd2,0x97,0x8c,0x76,0x1b,0x7d,0x6c,0xc7,0x6b,
  1346. 0xe8,0xff,0x3c,0xd6,0xa4,0x8f,0x80,0x2c,0xa4,0xfe,0x86,0x6d,0x65,0x77,0xc0,0x60,
  1347. 0xb3,0xf4,0x8f,0x53,0xd5,0xed,0x45,0x83,0x1d,0xc5,0xf8,0x8d,0x16,0x1d,0x5e,0x2a,
  1348. 0xa3,0x3a,0xbc,0x30,0x23,0xca,0x56,0xb4,0x39,0xbe,0x24,0x6b,0x04,0xb4,0x2d,0x0c,
  1349. 0xb5,0xfa,0x97,0x0d,0x17,0x84,0x2d,0x4b,0x16,0x03,0xfa,0xd9,0x27,0x61,0x89,0x5e,
  1350. 0xd4,0xc8,0xe1,0xc9,0xe4,0x9e,0x0e,0x3e,0x05,0x0e,0x99,0xf6,0x1b,0xcf,0xd1,0xbb,
  1351. 0xcf,0x58,0x51,0xa7,0x19,0xa8,0xe5,0x04,0xbd,0xe4,0x10,0x9f,0x83,0x5b,0xf4,0x5d,
  1352. 0xc9,0xe7,0x80,0x9e,0x16,0xe8,0x27,0xc7,0x8b,0x32,0x3c,0x28,0x64,0xf7,0xd4,0xfa,
  1353. 0xd0,0x37,0x75,0x15,0xb0,0x49,0x01,0xba,0x7c,0x70,0x05,0xcb,0x86,0xba,0x44,0x24,
  1354. 0xf4,0xa2,0xab,0x8e,0x71,0x3c,0x7a,0x20,0xd4,0x32,0x54,0xbe,0x68,0x64,0x9c,0x28,
  1355. 0xd2,0x3d,0xbf,0x17,0x52,0xc1,0xcd,0x50,0xae,0x24,0x5f,0x8d,0x69,0x66,0xad,0x13,
  1356. 0x2f,0x0f,0xdc,0xdc,0x1f,0xcc,0x4a,0x76,0xa6,0x87,0xa3,0xa3,0x71,0x90,0xfe,0x0f,
  1357. 0x5c,0x3e,0xc6,0xea,0xdd,0x74,0x11,0x07,0xb5,0x05,0xde,0x1b,0x82,0x71,0x24,0x25,
  1358. 0x58,0xc3,0x2e,0x29,0x9a,0x95,0x29,0x7e,0xc3,0x1a,0x09,0x06,0xbc,0x2d,0xf4,0x2c,
  1359. 0x96,0x19,0x05,0xc4,0x9b,0x92,0x4f,0xe6,0x8d,0x68,0x8f,0x89,0xe7,0x94,0x4a,0x7e,
  1360. 0x91,0x42,0xab,0x90,0x0d,0xeb,0xb2,0x93,0x55,0xb0,0x05,0xc7,0x96,0x65,0x23,0x74,
  1361. 0x04,0x5c,0xcd,0x77,0xff,0xb2,0xbe,0x71,0xcd,0xc9,0xc5,0x6f,0x6b,0xec,0x89,0x6e,
  1362. 0x25,0x3f,0x6f,0x95,0x1b,0x7a,0x99,0x66,0x44,0xc1,0x57,0xa7,0x4e,0x93,0x7c,0xf3,
  1363. 0xcd,0x6b,0x0b,0xa7,0x87,0xb5,0xdb,0xd0,0x7a,0xe1,0x45,0x1e,0xe4,0x46,0x57,0x33,
  1364. 0x28,0x2b,0x7a,0xa9,0x8e,0x77,0xfc,0xf6,0x64,0xec,0x75,0x7a,0xb6,0x4d,0x82,0x31,
  1365. 0x19,0xe9,0xdb,0x89,0x86,0x82,0x28,0xf9,0xd5,0x69,0xb4,0x28,0xf8,0x3c,0xbd,0xf7,
  1366. 0xe2,0x4a,0x76,0x8d,0x7e,0x39,0xe7,0xcf,0x93,0x8f,0xf2,0x20,0x53,0xf7,0x8d,0x6c,
  1367. 0x08,0x7a,0xab,0x6e,0xc7,0x7b,0x89,0xd4,0xfe,0xb9,0x8d,0x3e,0x4a,0xbe,0xd8,0x7f,
  1368. 0x0b,0x30,0x14,0xa5,0x1f,0x32,0xd7,0x85,0x59,0xef,0x5d,0xf4,0xea,0x16,0xeb,0xf6,
  1369. 0xda,0xba,0xf2,0x86,0xe3,0x7d,0xf4,0xa6,0xa6,0x35,0x73,0x9a,0x35,0xbd,0xbd,0x8c,
  1370. 0x49,0x09,0xcd,0x24,0x9e,0x9a,0x33,0x9b,0xb9,0xb3,0x0d,0x27,0x37,0x61,0x47,0xb2,
  1371. 0xe2,0xf9,0xd1,0x07,0xd0,0x4b,0x2d,0x60,0xd9,0x09,0xc4,0xcc,0x88,0xda,0xa6,0xef,
  1372. 0x56,0xd0,0x76,0xdc,0xac,0xd4,0x0c,0xf2,0xc6,0x56,0x79,0x6e,0x69,0xb8,0xda,0xf0,
  1373. 0xe8,0x7d,0xf4,0xab,0x5a,0xae,0x94,0xf4,0xe7,0xba,0xde,0x55,0xc5,0x7f,0xe8,0xff,
  1374. 0x4b,0xe8,0xff,0x58,0x0e,0x86,0x52,0x10,0xaa,0xfe,0x94,0xdd,0x14,0xec,0x9e,0xfa,
  1375. 0xae,0xc3,0x2e,0x66,0x5f,0x72,0x2c,0x52,0xa6,0xa1,0xfd,0x87,0x28,0x6e,0x0c,0xe3,
  1376. 0x46,0x49,0xf0,0xf7,0x26,0xa0,0x49,0xdc,0x12,0x7d,0x91,0x1f,0x64,0x56,0x44,0xee,
  1377. 0x42,0x94,0x8e,0x36,0x86,0x7f,0x8d,0x5e,0x75,0x70,0xb6,0xb8,0x1a,0x82,0x68,0x90,
  1378. 0xb1,0xe9,0x5e,0x86,0x66,0xc7,0xe2,0x23,0xaf,0xf1,0x01,0xc9,0x7b,0x18,0xb3,0xa8,
  1379. 0x5a,0x02,0x81,0x2c,0xac,0x81,0x0d,0x11,0x3d,0x46,0x02,0x50,0xe8,0x28,0xb6,0xf8,
  1380. 0x99,0x80,0x94,0x59,0xba,0x04,0x8e,0x1e,0xa1,0xaf,0x40,0x22,0x84,0xa1,0xcd,0xce,
  1381. 0x19,0x83,0xd5,0xa9,0xdb,0xd3,0xf0,0x76,0x63,0x73,0x8c,0x18,0xe0,0xc3,0xd4,0xd1,
  1382. 0x86,0xd2,0x8b,0xc8,0x44,0x3c,0x94,0x26,0xbb,0x76,0x5c,0x2e,0xd1,0xb3,0x4b,0x9c,
  1383. 0xc0,0x6f,0x03,0x68,0x91,0x72,0xa6,0xa3,0xfb,0x25,0xff,0x24,0x26,0xcb,0x76,0xb4,
  1384. 0x39,0x99,0x0f,0x1a,0x6b,0x70,0x8e,0x52,0xd0,0xae,0x28,0x8a,0xba,0x57,0xd4,0x96,
  1385. 0x61,0x7b,0xfb,0xcd,0x94,0x41,0x54,0xd5,0x2d,0x8c,0x47,0xb5,0xd2,0xb1,0xb3,0x99,
  1386. 0xb6,0xee,0xb9,0xc5,0xb7,0xc1,0xdf,0x37,0x89,0x9e,0xf2,0xdd,0x85,0xa3,0x1c,0x67,
  1387. 0xda,0xaa,0x67,0x3e,0x40,0x6f,0x5e,0x98,0xa5,0xd5,0x13,0x17,0x54,0x16,0x65,0xce,
  1388. 0xa9,0x2c,0x0f,0xd9,0x6b,0xb5,0xa2,0x44,0xca,0xbb,0x21,0x82,0xde,0xe3,0x52,0x18,
  1389. 0xf7,0xa3,0x0a,0x69,0x18,0x4f,0x0d,0x1b,0xd0,0x61,0xaf,0x3a,0xa3,0xd7,0x2a,0x8a,
  1390. 0xbf,0x61,0x43,0xd9,0x53,0x57,0x43,0xeb,0x30,0xeb,0xee,0x5b,0x85,0x67,0x1a,0x7b,
  1391. 0x67,0x52,0x34,0xb9,0xa0,0x5a,0x34,0x88,0xb1,0x61,0xf1,0x76,0x13,0xa7,0x18,0x95,
  1392. 0x48,0x88,0x12,0x9c,0xc7,0xde,0x26,0x43,0xe9,0x27,0xd8,0x80,0xf6,0x5d,0x5a,0xd6,
  1393. 0x50,0xa7,0x02,0xa3,0x33,0xc2,0xc3,0x5c,0xb8,0x47,0x2f,0x6b,0xfd,0x76,0x54,0x3c,
  1394. 0x9c,0xe8,0x2d,0xc9,0x9f,0x23,0x4a,0xfa,0x4c,0xc8,0xd5,0xd9,0x30,0xb3,0x9f,0xb9,
  1395. 0x44,0xba,0x43,0x64,0x1f,0x2d,0xce,0xdb,0xbd,0x1e,0xf6,0x11,0xbd,0xdd,0xd1,0xd1,
  1396. 0x34,0xbf,0xf7,0x90,0x0b,0xde,0xec,0xe1,0x66,0x7b,0x76,0xf4,0x0c,0x3d,0x27,0xb4,
  1397. 0xac,0x32,0xec,0x63,0xaf,0xee,0x68,0x46,0x38,0xc3,0x56,0xd3,0x88,0xe7,0x0b,0x30,
  1398. 0x31,0x0b,0x4c,0x86,0x81,0x26,0x3b,0x7a,0x70,0x51,0x3b,0x45,0x2f,0x9b,0x1d,0x22,
  1399. 0x40,0xbe,0x84,0xe4,0x23,0xa1,0x7b,0x0f,0xa2,0x11,0x6b,0x70,0x4d,0x2b,0x3a,0x8a,
  1400. 0xec,0x01,0x57,0x8c,0x24,0x27,0x9d,0xcd,0x81,0x02,0x31,0x8b,0x5f,0x86,0xfd,0x8b,
  1401. 0x38,0xf6,0x6e,0xbe,0x09,0xdb,0x5d,0x0b,0x35,0x51,0x05,0x88,0x2c,0x30,0x2c,0x1e,
  1402. 0xa9,0xc7,0xe2,0x83,0x98,0xac,0x2b,0xaf,0x89,0xc6,0x97,0xf6,0x8a,0x33,0xf4,0xab,
  1403. 0xc2,0xda,0x12,0x52,0xf2,0x1d,0x41,0x1d,0xe4,0x04,0x3d,0x11,0xc6,0x65,0xc5,0xa3,
  1404. 0x8d,0xcd,0xad,0x8c,0x7e,0x1e,0xa6,0xa5,0x2e,0xfe,0x8f,0xd0,0xa3,0x99,0xc3,0x03,
  1405. 0x1a,0xef,0xd0,0x9f,0x1c,0x6d,0x6c,0x6e,0x5d,0x6d,0x2d,0x7d,0x3f,0xfa,0x65,0x85,
  1406. 0xac,0x2f,0xf9,0x43,0xf4,0x6a,0xea,0xf9,0x63,0x39,0x57,0xd6,0x0c,0xb6,0x50,0xf9,
  1407. 0x90,0xd6,0xf4,0xed,0x81,0xe0,0x4a,0x45,0x18,0xeb,0x1f,0x1e,0x05,0x2d,0x16,0x62,
  1408. 0x03,0xfc,0x8e,0xea,0xba,0x35,0x7f,0x93,0x60,0xbb,0x21,0xd3,0x70,0x9f,0x3c,0xe8,
  1409. 0x0f,0x60,0x54,0x05,0xb6,0x7b,0xac,0xd2,0xbe,0x39,0x6d,0x31,0xc7,0x6e,0x36,0xd7,
  1410. 0xc0,0xcc,0x19,0xbd,0xbb,0x90,0xb3,0x07,0x6b,0x1b,0x6c,0xdd,0xf2,0x92,0x3e,0xd0,
  1411. 0x3b,0x4d,0x96,0x45,0x78,0x58,0xb7,0xcc,0x36,0x1b,0x32,0xa1,0x3f,0x79,0xd0,0x5b,
  1412. 0x8e,0x31,0xe4,0xe4,0x5e,0x5a,0x8b,0xcf,0x40,0xdc,0xa5,0x11,0x3d,0x31,0x68,0xed,
  1413. 0x67,0xc9,0xea,0x97,0x16,0x7e,0x31,0x5b,0x0d,0x10,0xe5,0x5a,0x62,0xc9,0xa2,0x27,
  1414. 0x4b,0x49,0x29,0xe1,0xb9,0x4a,0x9b,0x14,0xd1,0xd1,0x3f,0x72,0x27,0xb3,0x32,0xa2,
  1415. 0xcb,0x09,0x78,0xb8,0x4d,0x09,0x9b,0xe1,0x2a,0xfe,0x56,0x8f,0xcc,0x7a,0x18,0xa1,
  1416. 0x55,0xb9,0x82,0xec,0x94,0x2d,0xb7,0x20,0xed,0x6f,0xb5,0x3a,0x88,0xb5,0x72,0xfb,
  1417. 0xd9,0x14,0x30,0xa1,0x00,0xdd,0xfa,0x75,0x92,0xd0,0xc9,0x2f,0x87,0x2f,0x2e,0x3c,
  1418. 0x68,0x80,0x45,0x86,0x57,0xae,0x53,0x0c,0xc8,0xd2,0x9f,0x0f,0xdd,0x8e,0x14,0x3d,
  1419. 0xeb,0xd8,0xe7,0x30,0xb1,0x9d,0x34,0x47,0x65,0x99,0x3f,0xce,0x94,0xd0,0x55,0x1f,
  1420. 0xec,0x45,0x68,0xe5,0x21,0x64,0x73,0xec,0xdc,0x42,0x8f,0xa1,0x4a,0xb2,0x5f,0xff,
  1421. 0xb2,0xe4,0xeb,0xd8,0x97,0x29,0x5e,0x69,0x9d,0xec,0xa0,0xe7,0x47,0xc2,0x27,0x31,
  1422. 0x75,0x22,0x3b,0x1b,0xe8,0xe1,0x93,0x0f,0xd2,0x6e,0x44,0xff,0x54,0xf2,0x29,0x7f,
  1423. 0x3e,0xe0,0xc5,0x59,0x6f,0x1d,0x85,0x73,0x9b,0x8a,0x39,0x97,0x6b,0x0a,0xc2,0x3b,
  1424. 0x4b,0xd1,0x02,0xc9,0xb6,0xe1,0x34,0xde,0x7b,0xf0,0x3b,0x7b,0x90,0x9a,0x2b,0x9b,
  1425. 0xd3,0xa2,0x72,0x9e,0xac,0x7e,0xa7,0x70,0xa0,0xe9,0x1b,0x03,0x67,0xa9,0x19,0xf7,
  1426. 0x39,0x85,0xeb,0x9c,0x3e,0xe0,0xc1,0x3a,0xc5,0x9f,0x2d,0xd4,0x5e,0x0f,0x88,0x20,
  1427. 0xca,0x3a,0xc0,0x45,0xd2,0x76,0x55,0xe0,0x07,0x7e,0xec,0xf4,0x72,0xcb,0xfd,0xca,
  1428. 0x9b,0xe8,0x91,0xbd,0xfe,0x3e,0xf4,0x77,0xb0,0x7f,0x3a,0xfa,0x3f,0x96,0x73,0x49,
  1429. 0x2e,0x4c,0xdd,0x5e,0xb0,0x9c,0x4d,0x9e,0x21,0x9a,0x7e,0xa3,0xe0,0x6e,0x66,0x04,
  1430. 0xc9,0xa9,0xd1,0x37,0x70,0x1c,0x74,0x66,0xdb,0x20,0x17,0xca,0x56,0x2e,0xd1,0x5f,
  1431. 0xf3,0x0c,0xd9,0xed,0x77,0x2f,0x37,0x09,0x90,0x57,0xdd,0xa5,0x3c,0x22,0x5b,0xfc,
  1432. 0x16,0xc7,0x41,0x67,0xb6,0x17,0x58,0x8e,0x2b,0x7b,0xfb,0xcf,0x8c,0x65,0x5a,0xbc,
  1433. 0xdc,0x64,0xc7,0x4e,0xdc,0xa3,0x7a,0xdf,0x3e,0x21,0x59,0x66,0xa8,0x79,0x8d,0xe3,
  1434. 0xe0,0x8e,0x17,0xc4,0xe4,0x3c,0x4b,0x9f,0xea,0x87,0x1e,0x2a,0x86,0x01,0x49,0xf8,
  1435. 0x51,0x8f,0xdd,0xa2,0x2a,0x32,0x96,0xe7,0x1c,0x27,0xa2,0x0f,0x21,0x08,0xdb,0xa9,
  1436. 0x13,0x13,0x5e,0x7c,0x42,0x6a,0xf1,0x89,0x89,0x84,0xde,0xe9,0xd6,0x43,0x3d,0x97,
  1437. 0x3d,0x48,0x66,0x8f,0xe3,0x84,0xc0,0x92,0x09,0xfd,0xab,0x7a,0x7e,0xe4,0x78,0xf3,
  1438. 0xf7,0x48,0x52,0x3a,0xa3,0xa7,0x47,0x8d,0x07,0xa5,0x5d,0xbf,0x0f,0xc3,0x9f,0x41,
  1439. 0xff,0x82,0x9e,0xff,0xf8,0x99,0xcf,0xa1,0xb7,0x20,0x9c,0xf2,0x01,0xf4,0x2f,0x4b,
  1440. 0xfe,0x0e,0x21,0x01,0xe3,0x6f,0x44,0x3f,0x7d,0xf2,0x60,0xb7,0x28,0x77,0x60,0xde,
  1441. 0xe4,0x38,0x5c,0x13,0xab,0xd2,0x0b,0xe2,0xaf,0xb7,0x08,0xc2,0xb9,0x4d,0x8d,0x47,
  1442. 0xd4,0x1d,0x62,0x12,0x02,0x66,0xd0,0xc1,0xec,0x3b,0x38,0x0e,0x7b,0xa4,0x57,0xb8,
  1443. 0x90,0x7d,0x37,0xde,0x64,0x39,0x7b,0x1f,0xc6,0x6a,0xdf,0xac,0xe7,0xc6,0x70,0x3a,
  1444. 0x4a,0x2b,0xde,0xe7,0x58,0xce,0xcf,0x44,0x8f,0x7b,0x10,0x9c,0x6c,0x3c,0x9f,0x64,
  1445. 0x39,0x3f,0x13,0x3d,0x7e,0x3d,0xa4,0x24,0x1b,0xcf,0xef,0x66,0x39,0xff,0x03,0xca,
  1446. 0x1b,0xaa,0xdf,0x6a,0xd1,0xba,0xa4,0x00,0x00,0x00,0x00,0x49,0x45,0x4e,0x44,0xae,
  1447. 0x42,0x60,0x82 };
  1448. int tigr_font_size = (int)sizeof(tigr_font);
  1449. //////// End of inlined file: tigr_font.h ////////
  1450. #include <stdlib.h>
  1451. #include <stdarg.h>
  1452. #include <errno.h>
  1453. #include <stdio.h>
  1454. #ifdef _MSC_VER
  1455. #define vsnprintf _vsnprintf
  1456. #endif
  1457. TigrFont tigrStockFont;
  1458. TigrFont* tfont = &tigrStockFont;
  1459. // Converts 8-bit codepage entries into Unicode code points.
  1460. static int cp1252[] = {
  1461. 0x20ac, 0xfffd, 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021, 0x02c6, 0x2030, 0x0160, 0x2039, 0x0152,
  1462. 0xfffd, 0x017d, 0xfffd, 0xfffd, 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 0x02dc, 0x2122,
  1463. 0x0161, 0x203a, 0x0153, 0xfffd, 0x017e, 0x0178, 0x00a0, 0x00a1, 0x00a2, 0x00a3, 0x00a4, 0x00a5, 0x00a6,
  1464. 0x00a7, 0x00a8, 0x00a9, 0x00aa, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x00af, 0x00b0, 0x00b1, 0x00b2, 0x00b3,
  1465. 0x00b4, 0x00b5, 0x00b6, 0x00b7, 0x00b8, 0x00b9, 0x00ba, 0x00bb, 0x00bc, 0x00bd, 0x00be, 0x00bf, 0x00c0,
  1466. 0x00c1, 0x00c2, 0x00c3, 0x00c4, 0x00c5, 0x00c6, 0x00c7, 0x00c8, 0x00c9, 0x00ca, 0x00cb, 0x00cc, 0x00cd,
  1467. 0x00ce, 0x00cf, 0x00d0, 0x00d1, 0x00d2, 0x00d3, 0x00d4, 0x00d5, 0x00d6, 0x00d7, 0x00d8, 0x00d9, 0x00da,
  1468. 0x00db, 0x00dc, 0x00dd, 0x00de, 0x00df, 0x00e0, 0x00e1, 0x00e2, 0x00e3, 0x00e4, 0x00e5, 0x00e6, 0x00e7,
  1469. 0x00e8, 0x00e9, 0x00ea, 0x00eb, 0x00ec, 0x00ed, 0x00ee, 0x00ef, 0x00f0, 0x00f1, 0x00f2, 0x00f3, 0x00f4,
  1470. 0x00f5, 0x00f6, 0x00f7, 0x00f8, 0x00f9, 0x00fa, 0x00fb, 0x00fc, 0x00fd, 0x00fe, 0x00ff,
  1471. };
  1472. static int border(Tigr* bmp, int x, int y) {
  1473. TPixel top = tigrGet(bmp, 0, 0);
  1474. TPixel c = tigrGet(bmp, x, y);
  1475. return (c.r == top.r && c.g == top.g && c.b == top.b) || x >= bmp->w || y >= bmp->h;
  1476. }
  1477. static void scan(Tigr* bmp, int* x, int* y, int* rowh) {
  1478. while (*y < bmp->h) {
  1479. if (*x >= bmp->w) {
  1480. *x = 0;
  1481. (*y) += *rowh;
  1482. *rowh = 1;
  1483. }
  1484. if (!border(bmp, *x, *y))
  1485. return;
  1486. (*x)++;
  1487. }
  1488. }
  1489. /*
  1490. * Watermarks are encoded vertically in the alpha channel using seven pixels
  1491. * starting at x, y. The first and last alpha values contain the magic values
  1492. * 0b10101010 and 0b01010101 respectively.
  1493. */
  1494. static int readWatermark(Tigr* bmp, int x, int y, int* big, int* small) {
  1495. const int magicHeader = 0xAA;
  1496. const int magicFooter = 0x55;
  1497. unsigned char watermark[7];
  1498. for (int i = 0; i < 7; i++) {
  1499. TPixel c = tigrGet(bmp, x, y + i);
  1500. watermark[i] = c.a;
  1501. }
  1502. if (watermark[0] != magicHeader || watermark[6] != magicFooter) {
  1503. return 0;
  1504. }
  1505. *big = watermark[1] | (watermark[2] << 8) | (watermark[3] << 16) | (watermark[4] << 24);
  1506. *small = watermark[5];
  1507. return 1;
  1508. }
  1509. int tigrLoadGlyphs(TigrFont* font, int codepage) {
  1510. int x = 0;
  1511. int y = 0;
  1512. int w = 0;
  1513. int h = 0;
  1514. int rowh = 1;
  1515. TigrGlyph* g;
  1516. switch (codepage) {
  1517. case TCP_ASCII:
  1518. font->numGlyphs = 128 - 32;
  1519. break;
  1520. case TCP_1252:
  1521. font->numGlyphs = 256 - 32;
  1522. break;
  1523. case TCP_UTF32:
  1524. if (!readWatermark(font->bitmap, 0, 0, &font->numGlyphs, &rowh)) {
  1525. return 0;
  1526. }
  1527. h = rowh;
  1528. x = 1;
  1529. break;
  1530. default:
  1531. errno = EINVAL;
  1532. return 0;
  1533. }
  1534. font->glyphs = (TigrGlyph*)calloc(font->numGlyphs, sizeof(TigrGlyph));
  1535. for (int index = 0; index < font->numGlyphs; index++) {
  1536. // Look up the Unicode code point.
  1537. g = &font->glyphs[index];
  1538. if (codepage != TCP_UTF32) {
  1539. // Find the next glyph.
  1540. scan(font->bitmap, &x, &y, &rowh);
  1541. if (y >= font->bitmap->h) {
  1542. errno = EINVAL;
  1543. return 0;
  1544. }
  1545. // Scan the width and height
  1546. w = h = 0;
  1547. while (!border(font->bitmap, x + w, y)) {
  1548. w++;
  1549. }
  1550. while (!border(font->bitmap, x, y + h)) {
  1551. h++;
  1552. }
  1553. }
  1554. switch (codepage) {
  1555. case TCP_ASCII:
  1556. g->code = index + 32;
  1557. break;
  1558. case TCP_1252:
  1559. if (index < 96) {
  1560. g->code = index + 32;
  1561. } else {
  1562. g->code = cp1252[index - 96];
  1563. }
  1564. break;
  1565. case TCP_UTF32:
  1566. if (!readWatermark(font->bitmap, x, y, &g->code, &w)) {
  1567. // Maybe we are at the end of a row?
  1568. x = 0;
  1569. y += rowh;
  1570. if (!readWatermark(font->bitmap, x, y, &g->code, &w)) {
  1571. return 0;
  1572. }
  1573. }
  1574. x++;
  1575. break;
  1576. default:
  1577. return 0;
  1578. }
  1579. g->x = x;
  1580. g->y = y;
  1581. g->w = w;
  1582. g->h = h;
  1583. x += w;
  1584. if (h != font->glyphs[0].h) {
  1585. errno = EINVAL;
  1586. return 0;
  1587. }
  1588. if (h > rowh) {
  1589. rowh = h;
  1590. }
  1591. }
  1592. // Sort by code point.
  1593. for (int i = 1; i < font->numGlyphs; i++) {
  1594. int j = i;
  1595. TigrGlyph g = font->glyphs[i];
  1596. while (j > 0 && font->glyphs[j - 1].code > g.code) {
  1597. font->glyphs[j] = font->glyphs[j - 1];
  1598. j--;
  1599. }
  1600. font->glyphs[j] = g;
  1601. }
  1602. return 1;
  1603. }
  1604. TigrFont* tigrLoadFont(Tigr* bitmap, int codepage) {
  1605. TigrFont* font = (TigrFont*)calloc(1, sizeof(TigrFont));
  1606. font->bitmap = bitmap;
  1607. if (!tigrLoadGlyphs(font, codepage)) {
  1608. tigrFreeFont(font);
  1609. return NULL;
  1610. }
  1611. return font;
  1612. }
  1613. void tigrFreeFont(TigrFont* font) {
  1614. tigrFree(font->bitmap);
  1615. free(font->glyphs);
  1616. free(font);
  1617. }
  1618. static TigrGlyph* get(TigrFont* font, int code) {
  1619. unsigned lo = 0, hi = font->numGlyphs;
  1620. while (lo < hi) {
  1621. unsigned guess = (lo + hi) / 2;
  1622. if (code < font->glyphs[guess].code)
  1623. hi = guess;
  1624. else
  1625. lo = guess + 1;
  1626. }
  1627. if (lo == 0 || font->glyphs[lo - 1].code != code)
  1628. return &font->glyphs['?' - 32];
  1629. else
  1630. return &font->glyphs[lo - 1];
  1631. }
  1632. void tigrSetupFont(TigrFont* font) {
  1633. // Load the stock font if needed.
  1634. if (font == tfont && !tfont->bitmap) {
  1635. tfont->bitmap = tigrLoadImageMem(tigr_font, tigr_font_size);
  1636. tigrLoadGlyphs(tfont, 1252);
  1637. }
  1638. }
  1639. void tigrPrint(Tigr* dest, TigrFont* font, int x, int y, TPixel color, const char* text, ...) {
  1640. char tmp[1024];
  1641. TigrGlyph* g;
  1642. va_list args;
  1643. const char* p;
  1644. int start = x, c;
  1645. tigrSetupFont(font);
  1646. // Expand the formatting string.
  1647. va_start(args, text);
  1648. vsnprintf(tmp, sizeof(tmp), text, args);
  1649. tmp[sizeof(tmp) - 1] = 0;
  1650. va_end(args);
  1651. // Print each glyph.
  1652. p = tmp;
  1653. while (*p) {
  1654. p = tigrDecodeUTF8(p, &c);
  1655. if (c == '\r')
  1656. continue;
  1657. if (c == '\n') {
  1658. x = start;
  1659. y += tigrTextHeight(font, "");
  1660. continue;
  1661. }
  1662. g = get(font, c);
  1663. tigrBlitTint(dest, font->bitmap, x, y, g->x, g->y, g->w, g->h, color);
  1664. x += g->w;
  1665. }
  1666. }
  1667. int tigrTextWidth(TigrFont* font, const char* text) {
  1668. int x = 0, w = 0, c;
  1669. tigrSetupFont(font);
  1670. while (*text) {
  1671. text = tigrDecodeUTF8(text, &c);
  1672. if (c == '\n' || c == '\r') {
  1673. x = 0;
  1674. } else {
  1675. x += get(font, c)->w;
  1676. w = (x > w) ? x : w;
  1677. }
  1678. }
  1679. return w;
  1680. }
  1681. int tigrTextHeight(TigrFont* font, const char* text) {
  1682. int rowh, h, c;
  1683. tigrSetupFont(font);
  1684. h = rowh = get(font, 0)->h;
  1685. while (*text) {
  1686. text = tigrDecodeUTF8(text, &c);
  1687. if (c == '\n' && *text)
  1688. h += rowh;
  1689. }
  1690. return h;
  1691. }
  1692. //////// End of inlined file: tigr_print.c ////////
  1693. //////// Start of inlined file: tigr_win.c ////////
  1694. #ifndef TIGR_HEADLESS
  1695. //#include "tigr_internal.h"
  1696. #include <assert.h>
  1697. // not really windows stuff
  1698. TigrInternal* tigrInternal(Tigr* bmp) {
  1699. assert(bmp->handle);
  1700. return (TigrInternal*)(bmp + 1);
  1701. }
  1702. #ifdef _WIN32
  1703. #define WIN32_LEAN_AND_MEAN
  1704. #include <windows.h>
  1705. #include <shellapi.h>
  1706. #include <stdio.h>
  1707. #include <stdlib.h>
  1708. #include <stddef.h>
  1709. #ifdef _MSC_VER
  1710. #pragma comment(lib, "opengl32") // glViewport
  1711. #pragma comment(lib, "shell32") // CommandLineToArgvW
  1712. #pragma comment(lib, "user32") // SetWindowLong
  1713. #pragma comment(lib, "gdi32") // ChoosePixelFormat
  1714. #pragma comment(lib, "advapi32") // RegSetValueEx
  1715. #endif
  1716. #define WIDGET_SCALE 3
  1717. #define WIDGET_FADE 16
  1718. int main(int argc, char* argv[]);
  1719. #ifndef TIGR_DO_NOT_PRESERVE_WINDOW_POSITION
  1720. HKEY tigrRegKey;
  1721. #endif
  1722. #ifdef __TINYC__
  1723. #define CP_UTF8 65001
  1724. int WINAPI MultiByteToWideChar();
  1725. int WINAPI WideCharToMultiByte();
  1726. #endif
  1727. static wchar_t* unicode(const char* str) {
  1728. int len = MultiByteToWideChar(CP_UTF8, 0, str, -1, 0, 0);
  1729. wchar_t* dest = (wchar_t*)malloc(sizeof(wchar_t) * len);
  1730. MultiByteToWideChar(CP_UTF8, 0, str, -1, dest, len);
  1731. return dest;
  1732. }
  1733. void tigrError(Tigr* bmp, const char* message, ...) {
  1734. char tmp[1024];
  1735. va_list args;
  1736. va_start(args, message);
  1737. _vsnprintf(tmp, sizeof(tmp), message, args);
  1738. tmp[sizeof(tmp) - 1] = 0;
  1739. va_end(args);
  1740. MessageBoxW(bmp ? (HWND)bmp->handle : NULL, unicode(tmp), bmp ? tigrInternal(bmp)->wtitle : L"Error",
  1741. MB_OK | MB_ICONERROR);
  1742. exit(1);
  1743. }
  1744. void tigrEnterBorderlessWindowed(Tigr* bmp) {
  1745. // Enter borderless windowed mode.
  1746. MONITORINFO mi = { sizeof(mi) };
  1747. TigrInternal* win = tigrInternal(bmp);
  1748. GetWindowRect((HWND)bmp->handle, &win->oldPos);
  1749. GetMonitorInfo(MonitorFromWindow((HWND)bmp->handle, MONITOR_DEFAULTTONEAREST), &mi);
  1750. win->dwStyle = WS_VISIBLE | WS_POPUP;
  1751. SetWindowLong((HWND)bmp->handle, GWL_STYLE, win->dwStyle);
  1752. SetWindowPos((HWND)bmp->handle, HWND_TOP, mi.rcMonitor.left, mi.rcMonitor.top,
  1753. mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top, 0);
  1754. }
  1755. void tigrLeaveBorderlessWindowed(Tigr* bmp) {
  1756. TigrInternal* win = tigrInternal(bmp);
  1757. win->dwStyle = WS_VISIBLE | WS_OVERLAPPEDWINDOW;
  1758. SetWindowLong((HWND)bmp->handle, GWL_STYLE, win->dwStyle);
  1759. SetWindowPos((HWND)bmp->handle, NULL, win->oldPos.left, win->oldPos.top, win->oldPos.right - win->oldPos.left,
  1760. win->oldPos.bottom - win->oldPos.top, 0);
  1761. }
  1762. void tigrWinUpdateWidgets(Tigr* bmp, int dw, int dh) {
  1763. POINT pt;
  1764. int i, x, clicked = 0;
  1765. char str[8];
  1766. TPixel col;
  1767. TPixel off = tigrRGB(255, 255, 255);
  1768. TPixel on = tigrRGB(0, 200, 255);
  1769. TigrInternal* win = tigrInternal(bmp);
  1770. (void)dh;
  1771. tigrClear(win->widgets, tigrRGBA(0, 0, 0, 0));
  1772. if (!(win->dwStyle & WS_POPUP)) {
  1773. win->widgetsWanted = 0;
  1774. win->widgetAlpha = 0;
  1775. return;
  1776. }
  1777. // See if we want to be showing widgets or not.
  1778. GetCursorPos(&pt);
  1779. ScreenToClient((HWND)bmp->handle, &pt);
  1780. if (pt.y == 0)
  1781. win->widgetsWanted = 1;
  1782. if (pt.y > win->widgets->h * WIDGET_SCALE)
  1783. win->widgetsWanted = 0;
  1784. // Track the alpha.
  1785. if (win->widgetsWanted)
  1786. win->widgetAlpha = (win->widgetAlpha <= 255 - WIDGET_FADE) ? win->widgetAlpha + WIDGET_FADE : 255;
  1787. else
  1788. win->widgetAlpha = (win->widgetAlpha >= WIDGET_FADE) ? win->widgetAlpha - WIDGET_FADE : 0;
  1789. // Get relative coords.
  1790. pt.x -= (dw - win->widgets->w * WIDGET_SCALE);
  1791. pt.x /= WIDGET_SCALE;
  1792. pt.y /= WIDGET_SCALE;
  1793. tigrClear(win->widgets, tigrRGBA(0, 0, 0, win->widgetAlpha));
  1794. // Render it.
  1795. for (i = 0; i < 3; i++) {
  1796. switch (i) {
  1797. case 0:
  1798. str[0] = '_';
  1799. str[1] = 0;
  1800. break; // "_" (minimize)
  1801. case 1:
  1802. str[0] = (char)0xEF;
  1803. str[1] = (char)0xBF;
  1804. str[2] = (char)0xBD;
  1805. str[3] = 0;
  1806. break; // "[]" (maximize)
  1807. case 2:
  1808. str[0] = (char)0xC3;
  1809. str[1] = (char)0x97;
  1810. str[2] = 0;
  1811. break; // "x" (close)
  1812. }
  1813. x = win->widgets->w + (i - 3) * 12;
  1814. if (i == 2)
  1815. off = tigrRGB(255, 0, 0);
  1816. if (pt.x >= x && pt.x < x + 10 && pt.y < win->widgets->h) {
  1817. col = on;
  1818. if (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
  1819. clicked |= 1 << i;
  1820. } else {
  1821. col = off;
  1822. }
  1823. col.a = win->widgetAlpha;
  1824. tigrPrint(win->widgets, tfont, x, 2, col, str);
  1825. }
  1826. if (clicked & 1)
  1827. ShowWindow((HWND)bmp->handle, SW_MINIMIZE);
  1828. if (clicked & 2)
  1829. tigrLeaveBorderlessWindowed(bmp);
  1830. if (clicked & 4)
  1831. SendMessage((HWND)bmp->handle, WM_CLOSE, 0, 0);
  1832. }
  1833. void tigrUpdate(Tigr* bmp) {
  1834. MSG msg;
  1835. RECT rc;
  1836. int dw, dh;
  1837. TigrInternal* win = tigrInternal(bmp);
  1838. if (!win->shown) {
  1839. win->shown = 1;
  1840. UpdateWindow((HWND)bmp->handle);
  1841. ShowWindow((HWND)bmp->handle, SW_SHOW);
  1842. }
  1843. // Get the window size.
  1844. GetClientRect((HWND)bmp->handle, &rc);
  1845. dw = rc.right - rc.left;
  1846. dh = rc.bottom - rc.top;
  1847. // Update the widget overlay.
  1848. tigrWinUpdateWidgets(bmp, dw, dh);
  1849. if (!tigrGAPIBegin(bmp)) {
  1850. tigrGAPIPresent(bmp, dw, dh);
  1851. SwapBuffers(win->gl.dc);
  1852. tigrGAPIEnd(bmp);
  1853. }
  1854. memcpy(win->prev, win->keys, 256);
  1855. win->scrollDeltaX = 0;
  1856. win->scrollDeltaY = 0;
  1857. // Run the message pump.
  1858. while (PeekMessage(&msg, (HWND)bmp->handle, 0, 0, PM_REMOVE)) {
  1859. if (msg.message == WM_QUIT)
  1860. break;
  1861. TranslateMessage(&msg);
  1862. DispatchMessage(&msg);
  1863. }
  1864. }
  1865. typedef BOOL(APIENTRY* PFNWGLSWAPINTERVALFARPROC_)(int);
  1866. static PFNWGLSWAPINTERVALFARPROC_ wglSwapIntervalEXT_ = 0;
  1867. int tigrGAPIBegin(Tigr* bmp) {
  1868. TigrInternal* win = tigrInternal(bmp);
  1869. return wglMakeCurrent(win->gl.dc, win->gl.hglrc) ? 0 : -1;
  1870. }
  1871. int tigrGAPIEnd(Tigr* bmp) {
  1872. (void)bmp;
  1873. return wglMakeCurrent(NULL, NULL) ? 0 : -1;
  1874. }
  1875. static BOOL UnadjustWindowRectEx(LPRECT prc, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle) {
  1876. BOOL fRc;
  1877. RECT rc;
  1878. SetRectEmpty(&rc);
  1879. fRc = AdjustWindowRectEx(&rc, dwStyle, fMenu, dwExStyle);
  1880. if (fRc) {
  1881. prc->left -= rc.left;
  1882. prc->top -= rc.top;
  1883. prc->right -= rc.right;
  1884. prc->bottom -= rc.bottom;
  1885. }
  1886. return fRc;
  1887. }
  1888. LRESULT CALLBACK tigrWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
  1889. Tigr* bmp;
  1890. TigrInternal* win = NULL;
  1891. RECT rc;
  1892. int dw, dh;
  1893. GetClientRect(hWnd, &rc);
  1894. dw = rc.right - rc.left;
  1895. dh = rc.bottom - rc.top;
  1896. bmp = (Tigr*)GetPropW(hWnd, L"Tigr");
  1897. if (bmp)
  1898. win = tigrInternal(bmp);
  1899. switch (message) {
  1900. case WM_PAINT:
  1901. if (!tigrGAPIBegin(bmp)) {
  1902. tigrGAPIPresent(bmp, dw, dh);
  1903. SwapBuffers(win->gl.dc);
  1904. tigrGAPIEnd(bmp);
  1905. }
  1906. ValidateRect(hWnd, NULL);
  1907. break;
  1908. case WM_CLOSE:
  1909. if (win)
  1910. win->closed = 1;
  1911. break;
  1912. case WM_GETMINMAXINFO:
  1913. if (bmp) {
  1914. MINMAXINFO* info = (MINMAXINFO*)lParam;
  1915. RECT rc;
  1916. rc.left = 0;
  1917. rc.top = 0;
  1918. if (win->flags & TIGR_AUTO) {
  1919. rc.right = 32;
  1920. rc.bottom = 32;
  1921. } else {
  1922. int minscale = tigrEnforceScale(1, win->flags);
  1923. rc.right = bmp->w * minscale;
  1924. rc.bottom = bmp->h * minscale;
  1925. }
  1926. AdjustWindowRectEx(&rc, win->dwStyle, FALSE, 0);
  1927. info->ptMinTrackSize.x = rc.right - rc.left;
  1928. info->ptMinTrackSize.y = rc.bottom - rc.top;
  1929. }
  1930. return 0;
  1931. case WM_SIZING:
  1932. if (win) {
  1933. // Calculate scale-constrained sizes.
  1934. RECT* rc = (RECT*)lParam;
  1935. int dx, dy;
  1936. UnadjustWindowRectEx(rc, win->dwStyle, FALSE, 0);
  1937. dx = (rc->right - rc->left) % win->scale;
  1938. dy = (rc->bottom - rc->top) % win->scale;
  1939. switch (wParam) {
  1940. case WMSZ_LEFT:
  1941. rc->left += dx;
  1942. break;
  1943. case WMSZ_RIGHT:
  1944. rc->right -= dx;
  1945. break;
  1946. case WMSZ_TOP:
  1947. rc->top += dy;
  1948. break;
  1949. case WMSZ_TOPLEFT:
  1950. rc->left += dx;
  1951. rc->top += dy;
  1952. break;
  1953. case WMSZ_TOPRIGHT:
  1954. rc->right -= dx;
  1955. rc->top += dy;
  1956. break;
  1957. case WMSZ_BOTTOM:
  1958. rc->bottom -= dy;
  1959. break;
  1960. case WMSZ_BOTTOMLEFT:
  1961. rc->left += dx;
  1962. rc->bottom -= dy;
  1963. break;
  1964. case WMSZ_BOTTOMRIGHT:
  1965. rc->right -= dx;
  1966. rc->bottom -= dy;
  1967. break;
  1968. }
  1969. AdjustWindowRectEx(rc, win->dwStyle, FALSE, 0);
  1970. }
  1971. return TRUE;
  1972. case WM_SIZE:
  1973. if (win) {
  1974. if (wParam != SIZE_MINIMIZED) {
  1975. // Detect window size changes and update our bitmap accordingly.
  1976. dw = LOWORD(lParam);
  1977. dh = HIWORD(lParam);
  1978. if (win->flags & TIGR_AUTO) {
  1979. tigrResize(bmp, dw / win->scale, dh / win->scale);
  1980. } else {
  1981. win->scale = tigrEnforceScale(tigrCalcScale(bmp->w, bmp->h, dw, dh), win->flags);
  1982. }
  1983. tigrPosition(bmp, win->scale, dw, dh, win->pos);
  1984. }
  1985. // If someone tried to maximize us (e.g. via shortcut launch options),
  1986. // prefer instead to be borderless.
  1987. if (wParam == SIZE_MAXIMIZED) {
  1988. ShowWindow((HWND)bmp->handle, SW_NORMAL);
  1989. tigrEnterBorderlessWindowed(bmp);
  1990. }
  1991. }
  1992. return 0;
  1993. #ifndef TIGR_DO_NOT_PRESERVE_WINDOW_POSITION
  1994. case WM_WINDOWPOSCHANGED: {
  1995. // Save our position.
  1996. WINDOWPLACEMENT wp = { sizeof(WINDOWPLACEMENT) };
  1997. GetWindowPlacement(hWnd, &wp);
  1998. if (win->dwStyle & WS_POPUP)
  1999. wp.showCmd = SW_MAXIMIZE;
  2000. RegSetValueExW(tigrRegKey, win->wtitle, 0, REG_BINARY, (BYTE*)&wp, sizeof(wp));
  2001. return DefWindowProcW(hWnd, message, wParam, lParam);
  2002. }
  2003. #endif
  2004. case WM_ACTIVATE:
  2005. if (win) {
  2006. memset(win->keys, 0, 256);
  2007. memset(win->prev, 0, 256);
  2008. win->lastChar = 0;
  2009. }
  2010. return 0;
  2011. case WM_CHAR:
  2012. if (win) {
  2013. if (wParam == '\r') {
  2014. wParam = '\n';
  2015. }
  2016. int repeating = (HIWORD(lParam) & KF_REPEAT) == KF_REPEAT;
  2017. if (!repeating) {
  2018. win->lastChar = wParam;
  2019. }
  2020. }
  2021. return DefWindowProcW(hWnd, message, wParam, lParam);
  2022. case WM_MENUCHAR:
  2023. // Disable beep on Alt+Enter
  2024. if (LOWORD(wParam) == VK_RETURN)
  2025. return MNC_CLOSE << 16;
  2026. return DefWindowProcW(hWnd, message, wParam, lParam);
  2027. case WM_SYSKEYDOWN:
  2028. if (win) {
  2029. if (wParam == VK_RETURN) {
  2030. // Alt+Enter
  2031. if (win->dwStyle & WS_POPUP)
  2032. tigrLeaveBorderlessWindowed(bmp);
  2033. else
  2034. tigrEnterBorderlessWindowed(bmp);
  2035. return 0;
  2036. }
  2037. }
  2038. // fall-thru
  2039. case WM_KEYDOWN:
  2040. if (win)
  2041. win->keys[wParam] = 1;
  2042. return DefWindowProcW(hWnd, message, wParam, lParam);
  2043. case WM_SYSKEYUP:
  2044. // fall-thru
  2045. case WM_KEYUP:
  2046. if (win)
  2047. win->keys[wParam] = 0;
  2048. return DefWindowProcW(hWnd, message, wParam, lParam);
  2049. case WM_MOUSEWHEEL:
  2050. if (win)
  2051. win->scrollDeltaY += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
  2052. return DefWindowProcW(hWnd, message, wParam, lParam);
  2053. case WM_MOUSEHWHEEL:
  2054. if (win)
  2055. win->scrollDeltaX += (float)GET_WHEEL_DELTA_WPARAM(wParam) / (float)WHEEL_DELTA;
  2056. return DefWindowProcW(hWnd, message, wParam, lParam);
  2057. default:
  2058. return DefWindowProcW(hWnd, message, wParam, lParam);
  2059. }
  2060. return 0;
  2061. }
  2062. Tigr* tigrWindow(int w, int h, const char* title, int flags) {
  2063. WNDCLASSEXW wcex = { 0 };
  2064. int maxW, maxH, scale;
  2065. HWND hWnd;
  2066. DWORD dwStyle;
  2067. RECT rc;
  2068. Tigr* bmp;
  2069. TigrInternal* win;
  2070. #ifndef TIGR_DO_NOT_PRESERVE_WINDOW_POSITION
  2071. WINDOWPLACEMENT wp;
  2072. DWORD wpsize = sizeof(wp);
  2073. #endif
  2074. wchar_t* wtitle = unicode(title);
  2075. // Find our registry key.
  2076. #ifndef TIGR_DO_NOT_PRESERVE_WINDOW_POSITION
  2077. RegCreateKeyExW(HKEY_CURRENT_USER, L"Software\\TIGR", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
  2078. &tigrRegKey, NULL);
  2079. #endif
  2080. // Register a window class.
  2081. wcex.cbSize = sizeof(WNDCLASSEXW);
  2082. wcex.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  2083. wcex.lpfnWndProc = tigrWndProc;
  2084. wcex.hInstance = GetModuleHandle(NULL);
  2085. wcex.hIcon = NULL;
  2086. wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  2087. wcex.lpszClassName = L"TIGR";
  2088. RegisterClassExW(&wcex);
  2089. if (flags & TIGR_AUTO) {
  2090. // Always use a 1:1 pixel size.
  2091. scale = 1;
  2092. } else {
  2093. // See how big we can make it and still fit on-screen.
  2094. maxW = GetSystemMetrics(SM_CXSCREEN) * 3 / 4;
  2095. maxH = GetSystemMetrics(SM_CYSCREEN) * 3 / 4;
  2096. scale = tigrCalcScale(w, h, maxW, maxH);
  2097. }
  2098. scale = tigrEnforceScale(scale, flags);
  2099. // Get the final window size.
  2100. dwStyle = WS_OVERLAPPEDWINDOW;
  2101. rc.left = 0;
  2102. rc.top = 0;
  2103. rc.right = w * scale;
  2104. rc.bottom = h * scale;
  2105. AdjustWindowRect(&rc, dwStyle, FALSE);
  2106. // Make a window.
  2107. hWnd = CreateWindowW(L"TIGR", wtitle, dwStyle, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top,
  2108. NULL, NULL, wcex.hInstance, NULL);
  2109. if (!hWnd)
  2110. ExitProcess(1);
  2111. if (flags & TIGR_NOCURSOR) {
  2112. ShowCursor(FALSE);
  2113. }
  2114. // Wrap a bitmap around it.
  2115. bmp = tigrBitmap2(w, h, sizeof(TigrInternal));
  2116. bmp->handle = hWnd;
  2117. // Set up the Windows parts.
  2118. win = tigrInternal(bmp);
  2119. win->dwStyle = dwStyle;
  2120. win->wtitle = wtitle;
  2121. win->shown = 0;
  2122. win->closed = 0;
  2123. win->scale = scale;
  2124. win->lastChar = 0;
  2125. win->flags = flags;
  2126. win->p1 = win->p2 = win->p3 = 0;
  2127. win->p4 = 1;
  2128. win->widgetsWanted = 0;
  2129. win->widgetAlpha = 0;
  2130. win->widgetsScale = WIDGET_SCALE;
  2131. win->widgets = tigrBitmap(40, 14);
  2132. SetPropW(hWnd, L"Tigr", bmp);
  2133. tigrGAPICreate(bmp);
  2134. if (flags & TIGR_FULLSCREEN) {
  2135. tigrEnterBorderlessWindowed(bmp);
  2136. } else {
  2137. // Try and restore our window position.
  2138. #ifndef TIGR_DO_NOT_PRESERVE_WINDOW_POSITION
  2139. if (RegQueryValueExW(tigrRegKey, wtitle, NULL, NULL, (BYTE*)&wp, &wpsize) == ERROR_SUCCESS) {
  2140. if (wp.showCmd == SW_MAXIMIZE)
  2141. tigrEnterBorderlessWindowed(bmp);
  2142. else
  2143. SetWindowPlacement(hWnd, &wp);
  2144. }
  2145. #endif
  2146. }
  2147. wglSwapIntervalEXT_ = (PFNWGLSWAPINTERVALFARPROC_)wglGetProcAddress("wglSwapIntervalEXT");
  2148. if (wglSwapIntervalEXT_)
  2149. wglSwapIntervalEXT_(1);
  2150. return bmp;
  2151. }
  2152. void tigrFree(Tigr* bmp) {
  2153. if (bmp->handle) {
  2154. TigrInternal* win = tigrInternal(bmp);
  2155. tigrGAPIDestroy(bmp);
  2156. if (win->gl.hglrc && !wglDeleteContext(win->gl.hglrc)) {
  2157. tigrError(bmp, "Cannot delete OpenGL context.\n");
  2158. }
  2159. win->gl.hglrc = NULL;
  2160. if (win->gl.dc && !ReleaseDC((HWND)bmp->handle, win->gl.dc)) {
  2161. tigrError(bmp, "Cannot release OpenGL device context.\n");
  2162. }
  2163. win->gl.dc = NULL;
  2164. DestroyWindow((HWND)bmp->handle);
  2165. free(win->wtitle);
  2166. tigrFree(win->widgets);
  2167. }
  2168. free(bmp->pix);
  2169. free(bmp);
  2170. }
  2171. int tigrClosed(Tigr* bmp) {
  2172. TigrInternal* win = tigrInternal(bmp);
  2173. int val = win->closed;
  2174. win->closed = 0;
  2175. return val;
  2176. }
  2177. float tigrTime(void) {
  2178. static int first = 1;
  2179. static LARGE_INTEGER prev;
  2180. LARGE_INTEGER cnt, freq;
  2181. ULONGLONG diff;
  2182. QueryPerformanceCounter(&cnt);
  2183. QueryPerformanceFrequency(&freq);
  2184. if (first) {
  2185. first = 0;
  2186. prev = cnt;
  2187. }
  2188. diff = cnt.QuadPart - prev.QuadPart;
  2189. prev = cnt;
  2190. return (float)(diff / (double)freq.QuadPart);
  2191. }
  2192. void tigrMouse(Tigr* bmp, int* x, int* y, int* buttons) {
  2193. POINT pt;
  2194. TigrInternal* win;
  2195. win = tigrInternal(bmp);
  2196. GetCursorPos(&pt);
  2197. ScreenToClient((HWND)bmp->handle, &pt);
  2198. *x = (pt.x - win->pos[0]) / win->scale;
  2199. *y = (pt.y - win->pos[1]) / win->scale;
  2200. *buttons = 0;
  2201. if (GetFocus() != bmp->handle)
  2202. return;
  2203. if (GetAsyncKeyState(VK_LBUTTON) & 0x8000)
  2204. *buttons |= 1;
  2205. if (GetAsyncKeyState(VK_MBUTTON) & 0x8000)
  2206. *buttons |= 2;
  2207. if (GetAsyncKeyState(VK_RBUTTON) & 0x8000)
  2208. *buttons |= 4;
  2209. }
  2210. int tigrTouch(Tigr* bmp, TigrTouchPoint* points, int maxPoints) {
  2211. int buttons = 0;
  2212. if (maxPoints > 0) {
  2213. tigrMouse(bmp, &points[0].x, &points[1].y, &buttons);
  2214. }
  2215. return buttons ? 1 : 0;
  2216. }
  2217. void tigrScrollWheel(Tigr* bmp, float* x, float* y) {
  2218. TigrInternal* win;
  2219. win = tigrInternal(bmp);
  2220. if (x) {
  2221. *x = win->scrollDeltaX;
  2222. }
  2223. if (y) {
  2224. *y = win->scrollDeltaY;
  2225. }
  2226. }
  2227. static int tigrWinVK(int key) {
  2228. if (key >= 'A' && key <= 'Z')
  2229. return key;
  2230. if (key >= '0' && key <= '9')
  2231. return key;
  2232. switch (key) {
  2233. case TK_BACKSPACE:
  2234. return VK_BACK;
  2235. case TK_TAB:
  2236. return VK_TAB;
  2237. case TK_RETURN:
  2238. return VK_RETURN;
  2239. case TK_SHIFT:
  2240. return VK_SHIFT;
  2241. case TK_CONTROL:
  2242. return VK_CONTROL;
  2243. case TK_ALT:
  2244. return VK_MENU;
  2245. case TK_PAUSE:
  2246. return VK_PAUSE;
  2247. case TK_CAPSLOCK:
  2248. return VK_CAPITAL;
  2249. case TK_ESCAPE:
  2250. return VK_ESCAPE;
  2251. case TK_SPACE:
  2252. return VK_SPACE;
  2253. case TK_PAGEUP:
  2254. return VK_PRIOR;
  2255. case TK_PAGEDN:
  2256. return VK_NEXT;
  2257. case TK_END:
  2258. return VK_END;
  2259. case TK_HOME:
  2260. return VK_HOME;
  2261. case TK_LEFT:
  2262. return VK_LEFT;
  2263. case TK_UP:
  2264. return VK_UP;
  2265. case TK_RIGHT:
  2266. return VK_RIGHT;
  2267. case TK_DOWN:
  2268. return VK_DOWN;
  2269. case TK_INSERT:
  2270. return VK_INSERT;
  2271. case TK_DELETE:
  2272. return VK_DELETE;
  2273. case TK_LWIN:
  2274. return VK_LWIN;
  2275. case TK_RWIN:
  2276. return VK_RWIN;
  2277. // case TK_APPS: return VK_APPS; // this key doesn't exist on OS X
  2278. case TK_PAD0:
  2279. return VK_NUMPAD0;
  2280. case TK_PAD1:
  2281. return VK_NUMPAD1;
  2282. case TK_PAD2:
  2283. return VK_NUMPAD2;
  2284. case TK_PAD3:
  2285. return VK_NUMPAD3;
  2286. case TK_PAD4:
  2287. return VK_NUMPAD4;
  2288. case TK_PAD5:
  2289. return VK_NUMPAD5;
  2290. case TK_PAD6:
  2291. return VK_NUMPAD6;
  2292. case TK_PAD7:
  2293. return VK_NUMPAD7;
  2294. case TK_PAD8:
  2295. return VK_NUMPAD8;
  2296. case TK_PAD9:
  2297. return VK_NUMPAD9;
  2298. case TK_PADMUL:
  2299. return VK_MULTIPLY;
  2300. case TK_PADADD:
  2301. return VK_ADD;
  2302. case TK_PADENTER:
  2303. return VK_SEPARATOR;
  2304. case TK_PADSUB:
  2305. return VK_SUBTRACT;
  2306. case TK_PADDOT:
  2307. return VK_DECIMAL;
  2308. case TK_PADDIV:
  2309. return VK_DIVIDE;
  2310. case TK_F1:
  2311. return VK_F1;
  2312. case TK_F2:
  2313. return VK_F2;
  2314. case TK_F3:
  2315. return VK_F3;
  2316. case TK_F4:
  2317. return VK_F4;
  2318. case TK_F5:
  2319. return VK_F5;
  2320. case TK_F6:
  2321. return VK_F6;
  2322. case TK_F7:
  2323. return VK_F7;
  2324. case TK_F8:
  2325. return VK_F8;
  2326. case TK_F9:
  2327. return VK_F9;
  2328. case TK_F10:
  2329. return VK_F10;
  2330. case TK_F11:
  2331. return VK_F11;
  2332. case TK_F12:
  2333. return VK_F12;
  2334. case TK_NUMLOCK:
  2335. return VK_NUMLOCK;
  2336. case TK_SCROLL:
  2337. return VK_SCROLL;
  2338. case TK_LSHIFT:
  2339. return VK_LSHIFT;
  2340. case TK_RSHIFT:
  2341. return VK_RSHIFT;
  2342. case TK_LCONTROL:
  2343. return VK_LCONTROL;
  2344. case TK_RCONTROL:
  2345. return VK_RCONTROL;
  2346. case TK_LALT:
  2347. return VK_LMENU;
  2348. case TK_RALT:
  2349. return VK_RMENU;
  2350. case TK_SEMICOLON:
  2351. return VK_OEM_1;
  2352. case TK_EQUALS:
  2353. return VK_OEM_PLUS;
  2354. case TK_COMMA:
  2355. return VK_OEM_COMMA;
  2356. case TK_MINUS:
  2357. return VK_OEM_MINUS;
  2358. case TK_DOT:
  2359. return VK_OEM_PERIOD;
  2360. case TK_SLASH:
  2361. return VK_OEM_2;
  2362. case TK_BACKTICK:
  2363. return VK_OEM_3;
  2364. case TK_LSQUARE:
  2365. return VK_OEM_4;
  2366. case TK_BACKSLASH:
  2367. return VK_OEM_5;
  2368. case TK_RSQUARE:
  2369. return VK_OEM_6;
  2370. case TK_TICK:
  2371. return VK_OEM_7;
  2372. }
  2373. return 0;
  2374. }
  2375. int tigrKeyDown(Tigr* bmp, int key) {
  2376. TigrInternal* win;
  2377. int k = tigrWinVK(key);
  2378. if (GetFocus() != bmp->handle)
  2379. return 0;
  2380. win = tigrInternal(bmp);
  2381. return win->keys[k] && !win->prev[k];
  2382. }
  2383. int tigrKeyHeld(Tigr* bmp, int key) {
  2384. TigrInternal* win;
  2385. int k = tigrWinVK(key);
  2386. if (GetFocus() != bmp->handle)
  2387. return 0;
  2388. win = tigrInternal(bmp);
  2389. return win->keys[k];
  2390. }
  2391. int tigrReadChar(Tigr* bmp) {
  2392. TigrInternal* win = tigrInternal(bmp);
  2393. int c = win->lastChar;
  2394. win->lastChar = 0;
  2395. return c;
  2396. }
  2397. // We supply our own WinMain and just chain through to the user's
  2398. // real entry point.
  2399. #ifdef UNICODE
  2400. int CALLBACK wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
  2401. #else
  2402. int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  2403. #endif
  2404. {
  2405. int n, argc;
  2406. LPWSTR* wargv = CommandLineToArgvW(GetCommandLineW(), &argc);
  2407. char** argv = (char**)calloc(argc + 1, sizeof(int));
  2408. (void)hInstance;
  2409. (void)hPrevInstance;
  2410. (void)lpCmdLine;
  2411. (void)nCmdShow;
  2412. for (n = 0; n < argc; n++) {
  2413. int len = WideCharToMultiByte(CP_UTF8, 0, wargv[n], -1, 0, 0, NULL, NULL);
  2414. argv[n] = (char*)malloc(len);
  2415. WideCharToMultiByte(CP_UTF8, 0, wargv[n], -1, argv[n], len, NULL, NULL);
  2416. }
  2417. return main(argc, argv);
  2418. }
  2419. #endif
  2420. #endif // #ifndef TIGR_HEADLESS
  2421. //////// End of inlined file: tigr_win.c ////////
  2422. //////// Start of inlined file: tigr_osx.c ////////
  2423. #ifndef TIGR_HEADLESS
  2424. // originally based on https://github.com/jimon/osx_app_in_plain_c
  2425. //#include "tigr_internal.h"
  2426. #if __MACOS__
  2427. #pragma clang diagnostic push
  2428. #pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
  2429. //////// Start of inlined file: tigr_objc.h ////////
  2430. #ifndef TIGR_OBJC_H
  2431. #define TIGR_OBJC_H
  2432. #if defined(__IOS__) || defined(__MACOS__)
  2433. #if defined(__OBJC__) && __has_feature(objc_arc)
  2434. #error "Can't compile as objective-c code!"
  2435. #endif
  2436. // ABI is a bit different between platforms
  2437. #ifdef __arm64__
  2438. #define abi_objc_msgSend_stret objc_msgSend
  2439. #else
  2440. #define abi_objc_msgSend_stret objc_msgSend_stret
  2441. #endif
  2442. #ifdef __i386__
  2443. #define abi_objc_msgSend_fpret objc_msgSend_fpret
  2444. #else
  2445. #define abi_objc_msgSend_fpret objc_msgSend
  2446. #endif
  2447. #define objc_msgSendSuper_t(RET, ...) ((RET(*)(struct objc_super*, SEL, ##__VA_ARGS__))objc_msgSendSuper)
  2448. #define objc_msgSend_t(RET, ...) ((RET(*)(id, SEL, ##__VA_ARGS__))objc_msgSend)
  2449. #define objc_msgSend_stret_t(RET, ...) ((RET(*)(id, SEL, ##__VA_ARGS__))abi_objc_msgSend_stret)
  2450. #define objc_msgSend_id objc_msgSend_t(id)
  2451. #define objc_msgSend_void objc_msgSend_t(void)
  2452. #define objc_msgSend_void_id objc_msgSend_t(void, id)
  2453. #define objc_msgSend_void_bool objc_msgSend_t(void, bool)
  2454. #define sel(NAME) sel_registerName(NAME)
  2455. #define class(NAME) ((id)objc_getClass(NAME))
  2456. #define makeClass(NAME, SUPER) objc_allocateClassPair((Class)objc_getClass(SUPER), NAME, 0)
  2457. // Check here to get the signature right: https://nshipster.com/type-encodings/
  2458. #define addMethod(CLASS, NAME, IMPL, SIGNATURE) \
  2459. if (!class_addMethod(CLASS, sel(NAME), (IMP)(IMPL), (SIGNATURE))) \
  2460. assert(false)
  2461. #define addIvar(CLASS, NAME, SIZE, SIGNATURE) \
  2462. if (!class_addIvar(CLASS, NAME, SIZE, rint(log2(SIZE)), SIGNATURE)) \
  2463. assert(false)
  2464. #define objc_alloc(CLASS) objc_msgSend_id(class(CLASS), sel("alloc"))
  2465. #if __LP64__ || NS_BUILD_32_LIKE_64
  2466. #define NSIntegerEncoding "q"
  2467. #define NSUIntegerEncoding "L"
  2468. #else
  2469. #define NSIntegerEncoding "i"
  2470. #define NSUIntegerEncoding "I"
  2471. #endif
  2472. #endif // defined(__IOS__) || defined (__MACOS__)
  2473. #endif // TIGR_OBJC_H
  2474. //////// End of inlined file: tigr_objc.h ////////
  2475. #pragma clang diagnostic pop
  2476. #include <assert.h>
  2477. #include <limits.h>
  2478. #include <math.h>
  2479. #include <stdarg.h>
  2480. #include <stdbool.h>
  2481. #include <stdint.h>
  2482. #include <stdio.h>
  2483. #include <stdlib.h>
  2484. #include <CoreFoundation/CoreFoundation.h>
  2485. #include <CoreGraphics/CoreGraphics.h>
  2486. #include <mach/mach_time.h>
  2487. #include <objc/NSObjCRuntime.h>
  2488. #include <objc/message.h>
  2489. #include <objc/objc.h>
  2490. #include <objc/runtime.h>
  2491. #include <CoreGraphics/CGBase.h>
  2492. #include <CoreGraphics/CGGeometry.h>
  2493. typedef CGPoint NSPoint;
  2494. typedef CGSize NSSize;
  2495. typedef CGRect NSRect;
  2496. enum {
  2497. NSKeyDown = 10,
  2498. NSKeyDownMask = 1 << NSKeyDown,
  2499. NSKeyUp = 11,
  2500. NSKeyUpMask = 1 << NSKeyUp,
  2501. };
  2502. NSUInteger NSAllEventMask = NSUIntegerMax;
  2503. extern id NSApp;
  2504. extern id const NSDefaultRunLoopMode;
  2505. #define NSApplicationActivationPolicyRegular 0
  2506. bool terminated = false;
  2507. static double _tigrTimestamp = 0;
  2508. double _currentMediaTime(void) {
  2509. uint64_t now = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
  2510. double current = now * 1.0E-9;
  2511. return current;
  2512. }
  2513. TigrInternal* _tigrInternalFromWindowDelegate(id wdg) {
  2514. Tigr* bmp = 0;
  2515. object_getInstanceVariable(wdg, "tigrHandle", (void**)&bmp);
  2516. return bmp ? tigrInternal(bmp) : NULL;
  2517. }
  2518. TigrInternal* _tigrInternalFromWindow(id window) {
  2519. if (!window)
  2520. return NULL;
  2521. id wdg = objc_msgSend_id(window, sel("delegate"));
  2522. if (!wdg)
  2523. return NULL;
  2524. return _tigrInternalFromWindowDelegate(wdg);
  2525. }
  2526. NSUInteger applicationShouldTerminate(id self, SEL sel, id sender) {
  2527. terminated = true;
  2528. return 0;
  2529. }
  2530. void windowWillClose(id self, SEL _sel, id notification) {
  2531. NSUInteger value = true;
  2532. object_setInstanceVariable(self, "closed", (void*)value);
  2533. object_setInstanceVariable(self, "tigrHandle", (void*)0);
  2534. }
  2535. void windowDidEnterFullScreen(id self, SEL _sel, id notification) {
  2536. NSUInteger value = true;
  2537. object_setInstanceVariable(self, "visible", (void*)value);
  2538. }
  2539. void windowDidResize(id self, SEL _sel, id notification) {
  2540. TigrInternal* win;
  2541. Tigr* bmp = 0;
  2542. object_getInstanceVariable(self, "tigrHandle", (void**)&bmp);
  2543. win = bmp ? tigrInternal(bmp) : NULL;
  2544. if (win) {
  2545. win->mouseButtons = 0;
  2546. }
  2547. }
  2548. void windowDidBecomeKey(id self, SEL _sel, id notification) {
  2549. TigrInternal* win;
  2550. Tigr* bmp = 0;
  2551. object_getInstanceVariable(self, "tigrHandle", (void**)&bmp);
  2552. win = bmp ? tigrInternal(bmp) : NULL;
  2553. if (win) {
  2554. memset(win->keys, 0, 256);
  2555. memset(win->prev, 0, 256);
  2556. win->lastChar = 0;
  2557. win->mouseButtons = 0;
  2558. }
  2559. }
  2560. void onFrame(id self, SEL _sel, id displayLink) {
  2561. double timestamp = objc_msgSend_t(double)(displayLink, sel("timestamp"));
  2562. TigrInternal* win = _tigrInternalFromWindowDelegate(self);
  2563. if (win == NULL) {
  2564. return;
  2565. }
  2566. win->frameTime = timestamp;
  2567. }
  2568. void mouseEntered(id self, SEL _sel, id event) {
  2569. id window = objc_msgSend_id(event, sel("window"));
  2570. TigrInternal* win = _tigrInternalFromWindow(window);
  2571. if (win) {
  2572. win->mouseInView = 1;
  2573. if (win->flags & TIGR_NOCURSOR) {
  2574. objc_msgSend_id(class("NSCursor"), sel("hide"));
  2575. }
  2576. }
  2577. }
  2578. void mouseExited(id self, SEL _sel, id event) {
  2579. id window = objc_msgSend_id(event, sel("window"));
  2580. TigrInternal* win = _tigrInternalFromWindow(window);
  2581. if (win) {
  2582. win->mouseInView = 0;
  2583. if (win->flags & TIGR_NOCURSOR) {
  2584. objc_msgSend_id(class("NSCursor"), sel("unhide"));
  2585. }
  2586. }
  2587. }
  2588. bool _tigrIsWindowClosed(id window) {
  2589. id wdg = objc_msgSend_id(window, sel("delegate"));
  2590. if (!wdg)
  2591. return false;
  2592. NSUInteger value = 0;
  2593. object_getInstanceVariable(wdg, "closed", (void**)&value);
  2594. return value ? true : false;
  2595. }
  2596. bool _tigrIsWindowVisible(id window) {
  2597. id wdg = objc_msgSend_id(window, sel("delegate"));
  2598. if (!wdg)
  2599. return false;
  2600. NSUInteger value = 0;
  2601. object_getInstanceVariable(wdg, "visible", (void**)&value);
  2602. return value ? true : false;
  2603. }
  2604. static bool tigrOSXInited = false;
  2605. static id autoreleasePool = NULL;
  2606. #ifdef DEBUG
  2607. static void _showPools(const char* context) {
  2608. fprintf(stderr, "NSAutoreleasePool@%s:\n", context);
  2609. objc_msgSend(class("NSAutoreleasePool"), sel("showPools"));
  2610. }
  2611. #define showPools(x) _showPools((x))
  2612. #else
  2613. #define showPools(x)
  2614. #endif
  2615. static id pushPool(void) {
  2616. id pool = objc_msgSend_id(class("NSAutoreleasePool"), sel("alloc"));
  2617. return objc_msgSend_id(pool, sel("init"));
  2618. }
  2619. static void popPool(id pool) {
  2620. objc_msgSend_void(pool, sel("drain"));
  2621. }
  2622. void _tigrCleanupOSX(void) {
  2623. showPools("cleanup");
  2624. popPool(autoreleasePool);
  2625. }
  2626. void tigrInitOSX(void) {
  2627. if (tigrOSXInited)
  2628. return;
  2629. atexit(&_tigrCleanupOSX);
  2630. autoreleasePool = pushPool();
  2631. showPools("init start");
  2632. objc_msgSend_id(class("NSApplication"), sel("sharedApplication"));
  2633. objc_msgSend_t(void, NSInteger)(NSApp, sel("setActivationPolicy:"), NSApplicationActivationPolicyRegular);
  2634. Class appDelegateClass = makeClass("AppDelegate", "NSObject");
  2635. addMethod(appDelegateClass, "applicationShouldTerminate", applicationShouldTerminate, NSUIntegerEncoding "@:@");
  2636. id dgAlloc = objc_msgSend_id((id)appDelegateClass, sel("alloc"));
  2637. id dg = objc_msgSend_id(dgAlloc, sel("init"));
  2638. objc_msgSend_void_id(NSApp, sel("setDelegate:"), dg);
  2639. objc_msgSend_void(NSApp, sel("finishLaunching"));
  2640. id menuBar = objc_alloc("NSMenu");
  2641. menuBar = objc_msgSend_id(menuBar, sel("init"));
  2642. id appMenuItem = objc_alloc("NSMenuItem");
  2643. appMenuItem = objc_msgSend_id(appMenuItem, sel("init"));
  2644. objc_msgSend_void_id(menuBar, sel("addItem:"), appMenuItem);
  2645. objc_msgSend_t(id, id)(NSApp, sel("setMainMenu:"), menuBar);
  2646. id processInfo = objc_msgSend_id(class("NSProcessInfo"), sel("processInfo"));
  2647. id appName = objc_msgSend_id(processInfo, sel("processName"));
  2648. id appMenu = objc_alloc("NSMenu");
  2649. appMenu = objc_msgSend_t(id, id)(appMenu, sel("initWithTitle:"), appName);
  2650. id quitTitlePrefixString =
  2651. objc_msgSend_t(id, const char*)(class("NSString"), sel("stringWithUTF8String:"), "Quit ");
  2652. id quitTitle = objc_msgSend_t(id, id)(quitTitlePrefixString, sel("stringByAppendingString:"), appName);
  2653. id quitMenuItemKey = objc_msgSend_t(id, const char*)(class("NSString"), sel("stringWithUTF8String:"), "q");
  2654. id quitMenuItem = objc_alloc("NSMenuItem");
  2655. quitMenuItem = objc_msgSend_t(id, id, SEL, id)(quitMenuItem, sel("initWithTitle:action:keyEquivalent:"), quitTitle,
  2656. sel("terminate:"), quitMenuItemKey);
  2657. objc_msgSend_void_id(appMenu, sel("addItem:"), quitMenuItem);
  2658. objc_msgSend_void_id(appMenuItem, sel("setSubmenu:"), appMenu);
  2659. tigrOSXInited = true;
  2660. showPools("init end");
  2661. }
  2662. void tigrError(Tigr* bmp, const char* message, ...) {
  2663. char tmp[1024];
  2664. va_list args;
  2665. va_start(args, message);
  2666. vsnprintf(tmp, sizeof(tmp), message, args);
  2667. tmp[sizeof(tmp) - 1] = 0;
  2668. va_end(args);
  2669. printf("tigr fatal error: %s\n", tmp);
  2670. exit(1);
  2671. }
  2672. NSSize _tigrContentBackingSize(id window) {
  2673. id contentView = objc_msgSend_id(window, sel("contentView"));
  2674. NSRect rect = objc_msgSend_stret_t(NSRect)(contentView, sel("frame"));
  2675. rect = objc_msgSend_stret_t(NSRect, NSRect)(contentView, sel("convertRectToBacking:"), rect);
  2676. return rect.size;
  2677. }
  2678. enum {
  2679. NSWindowStyleMaskTitled = 1 << 0,
  2680. NSWindowStyleMaskClosable = 1 << 1,
  2681. NSWindowStyleMaskMiniaturizable = 1 << 2,
  2682. NSWindowStyleMaskResizable = 1 << 3,
  2683. NSWindowStyleRegular = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable |
  2684. NSWindowStyleMaskResizable,
  2685. NSWindowStyleMaskFullSizeContentView = 1 << 15
  2686. };
  2687. Tigr* tigrWindow(int w, int h, const char* title, int flags) {
  2688. Tigr* bmp;
  2689. TigrInternal* win;
  2690. tigrInitOSX();
  2691. NSUInteger windowStyleMask = NSWindowStyleRegular & ~NSWindowStyleMaskMiniaturizable;
  2692. // In AUTO mode, window follows requested size, unless downscaled by tigrEnforceScale below.
  2693. int windowScale = 1;
  2694. // In non-AUTO mode, see how big we can make it and still fit on-screen.
  2695. if ((flags & TIGR_AUTO) == 0) {
  2696. CGRect mainMonitor = CGDisplayBounds(CGMainDisplayID());
  2697. int maxW = CGRectGetWidth(mainMonitor);
  2698. int maxH = CGRectGetHeight(mainMonitor);
  2699. NSRect screen = { { 0, 0 }, { maxW, maxH } };
  2700. NSRect content = objc_msgSend_stret_t(NSRect, NSRect, NSUInteger)(
  2701. class("NSWindow"), sel("contentRectForFrameRect:styleMask:"), screen, windowStyleMask);
  2702. windowScale = tigrCalcScale(w, h, content.size.width, content.size.height);
  2703. }
  2704. windowScale = tigrEnforceScale(windowScale, flags);
  2705. NSRect rect = { { 0, 0 }, { w * windowScale, h * windowScale } };
  2706. id windowAlloc = objc_msgSend_id(class("NSWindow"), sel("alloc"));
  2707. id window = ((id(*)(id, SEL, NSRect, NSUInteger, NSUInteger, BOOL))objc_msgSend)(
  2708. windowAlloc, sel("initWithContentRect:styleMask:backing:defer:"), rect, windowStyleMask, 2, NO);
  2709. objc_msgSend_void_bool(window, sel("setReleasedWhenClosed:"), NO);
  2710. Class WindowDelegateClass = objc_allocateClassPair((Class)objc_getClass("NSObject"), "WindowDelegate", 0);
  2711. addIvar(WindowDelegateClass, "closed", sizeof(NSUInteger), NSUIntegerEncoding);
  2712. addIvar(WindowDelegateClass, "visible", sizeof(NSUInteger), NSUIntegerEncoding);
  2713. addIvar(WindowDelegateClass, "tigrHandle", sizeof(void*), "ˆv");
  2714. addMethod(WindowDelegateClass, "windowWillClose:", windowWillClose, "v@:@");
  2715. addMethod(WindowDelegateClass, "windowDidEnterFullScreen:", windowDidEnterFullScreen, "v@:@");
  2716. addMethod(WindowDelegateClass, "windowDidResize:", windowDidResize, "v@:@");
  2717. addMethod(WindowDelegateClass, "windowDidBecomeKey:", windowDidBecomeKey, "v@:@");
  2718. addMethod(WindowDelegateClass, "mouseEntered:", mouseEntered, "v@:@");
  2719. addMethod(WindowDelegateClass, "mouseExited:", mouseExited, "v@:@");
  2720. addMethod(WindowDelegateClass, "onFrame:", onFrame, "v@:@");
  2721. id wdgAlloc = objc_msgSend_id((id)WindowDelegateClass, sel("alloc"));
  2722. id wdg = objc_msgSend_id(wdgAlloc, sel("init"));
  2723. if (flags & TIGR_FULLSCREEN) {
  2724. objc_msgSend_void_id(window, sel("toggleFullScreen:"), window);
  2725. if (flags & TIGR_NOCURSOR) {
  2726. objc_msgSend_id(class("NSCursor"), sel("hide"));
  2727. }
  2728. } else {
  2729. NSUInteger value = true;
  2730. object_setInstanceVariable(wdg, "visible", (void*)value);
  2731. }
  2732. objc_msgSend_void_id(window, sel("setDelegate:"), wdg);
  2733. id contentView = objc_msgSend_id(window, sel("contentView"));
  2734. objc_msgSend_void_bool(contentView, sel("setWantsLayer:"), NO);
  2735. bool useDisplayLink = objc_msgSend_t(bool, SEL)(class("NSView"), sel("instancesRespondToSelector:"),
  2736. sel("displayLinkWithTarget:selector:"));
  2737. if (useDisplayLink) {
  2738. // Use display link to pace frames, if possible
  2739. id link =
  2740. objc_msgSend_t(id, id, SEL)(contentView, sel("displayLinkWithTarget:selector:"), wdg, sel("onFrame:"));
  2741. id runLoop = objc_msgSend_id(class("NSRunLoop"), sel("currentRunLoop"));
  2742. objc_msgSend_t(void, id, id)(link, sel("addToRunLoop:forMode:"), runLoop, NSDefaultRunLoopMode);
  2743. objc_msgSend_void_bool(link, sel("setPaused:"), NO);
  2744. }
  2745. int wantsHighRes = (flags & TIGR_RETINA);
  2746. objc_msgSend_void_bool(contentView, sel("setWantsBestResolutionOpenGLSurface:"), wantsHighRes);
  2747. NSPoint point = { 20, 20 };
  2748. ((void (*)(id, SEL, NSPoint))objc_msgSend)(window, sel("cascadeTopLeftFromPoint:"), point);
  2749. id titleString = objc_msgSend_t(id, const char*)(class("NSString"), sel("stringWithUTF8String:"), title);
  2750. objc_msgSend_void_id(window, sel("setTitle:"), titleString);
  2751. uint32_t glAttributes[] = { 8, 24, // NSOpenGLPFAColorSize, 24,
  2752. 11, 8, // NSOpenGLPFAAlphaSize, 8,
  2753. 5, // NSOpenGLPFADoubleBuffer,
  2754. 73, // NSOpenGLPFAAccelerated,
  2755. // 72, // NSOpenGLPFANoRecovery,
  2756. // 55, 1, // NSOpenGLPFASampleBuffers, 1,
  2757. // 56, 4, // NSOpenGLPFASamples, 4,
  2758. 99, 0x3200, // NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
  2759. // 70, 0x00020400, // NSOpenGLPFARendererID, kCGLRendererGenericFloatID
  2760. 0 };
  2761. id pixelFormat = objc_alloc("NSOpenGLPixelFormat");
  2762. pixelFormat = objc_msgSend_t(id, const uint32_t*)(pixelFormat, sel("initWithAttributes:"), glAttributes);
  2763. objc_msgSend_void(pixelFormat, sel("autorelease"));
  2764. id openGLContext = objc_alloc("NSOpenGLContext");
  2765. openGLContext = objc_msgSend_t(id, id, id)(openGLContext, sel("initWithFormat:shareContext:"), pixelFormat, nil);
  2766. objc_msgSend_void_id(openGLContext, sel("setView:"), contentView);
  2767. objc_msgSend_void_id(window, sel("makeKeyAndOrderFront:"), window);
  2768. objc_msgSend_void_bool(window, sel("setAcceptsMouseMovedEvents:"), YES);
  2769. id blackColor = objc_msgSend_id(class("NSColor"), sel("blackColor"));
  2770. objc_msgSend_void_id(window, sel("setBackgroundColor:"), blackColor);
  2771. objc_msgSend_void_bool(NSApp, sel("activateIgnoringOtherApps:"), YES);
  2772. NSSize windowContentSize = _tigrContentBackingSize(window);
  2773. // In AUTO mode, always use a 1:1 pixel size, unless downscaled by tigrEnforceScale below.
  2774. int bitmapScale = 1;
  2775. // In non-AUTO mode, scale based on backing size
  2776. if ((flags & TIGR_AUTO) == 0) {
  2777. bitmapScale = tigrEnforceScale(tigrCalcScale(w, h, windowContentSize.width, windowContentSize.height), flags);
  2778. } else {
  2779. // In AUTO mode, bitmap size follows window size
  2780. w = windowContentSize.width / windowScale;
  2781. h = windowContentSize.height / windowScale;
  2782. bitmapScale = tigrEnforceScale(bitmapScale, flags);
  2783. }
  2784. bmp = tigrBitmap2(w, h, sizeof(TigrInternal));
  2785. bmp->handle = window;
  2786. // Set the handle
  2787. object_setInstanceVariable(wdg, "tigrHandle", (void*)bmp);
  2788. {
  2789. #define NSTrackingMouseEnteredAndExited 1
  2790. #define NSTrackingActiveInKeyWindow 0x20
  2791. #define NSTrackingInVisibleRect 0x200
  2792. int trackingFlags = NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect;
  2793. id trackingArea = objc_msgSend_id(class("NSTrackingArea"), sel("alloc"));
  2794. trackingArea = objc_msgSend_t(id, NSRect, int, id, id)(
  2795. trackingArea, sel("initWithRect:options:owner:userInfo:"), rect, trackingFlags, wdg, 0);
  2796. objc_msgSend_void_id(contentView, sel("addTrackingArea:"), trackingArea);
  2797. }
  2798. // Set up the Windows parts.
  2799. win = tigrInternal(bmp);
  2800. win->shown = 0;
  2801. win->closed = 0;
  2802. win->scale = bitmapScale;
  2803. win->lastChar = 0;
  2804. win->flags = flags;
  2805. win->p1 = win->p2 = win->p3 = 0;
  2806. win->p4 = 1;
  2807. win->widgetsWanted = 0;
  2808. win->widgetAlpha = 0;
  2809. win->widgetsScale = 0;
  2810. win->widgets = 0;
  2811. win->gl.gl_legacy = 0;
  2812. win->gl.glContext = openGLContext;
  2813. win->mouseButtons = 0;
  2814. win->mouseInView = 0;
  2815. win->frameTime = 0;
  2816. tigrPosition(bmp, win->scale, bmp->w, bmp->h, win->pos);
  2817. GLint swapInterval = 1;
  2818. NSInteger NSOpenGLCPSwapInterval = 222;
  2819. objc_msgSend_t(void, GLint*, NSInteger)(openGLContext, sel("setValues:forParameter:"), &swapInterval,
  2820. NSOpenGLCPSwapInterval);
  2821. objc_msgSend_void(openGLContext, sel("makeCurrentContext"));
  2822. tigrGAPICreate(bmp);
  2823. return bmp;
  2824. }
  2825. void tigrFree(Tigr* bmp) {
  2826. if (bmp->handle) {
  2827. TigrInternal* win = tigrInternal(bmp);
  2828. tigrGAPIDestroy(bmp);
  2829. id window = (id)bmp->handle;
  2830. if (!_tigrIsWindowClosed(window) && !terminated) {
  2831. objc_msgSend_void(window, sel("close"));
  2832. }
  2833. if (win->flags & TIGR_NOCURSOR) {
  2834. objc_msgSend_id(class("NSCursor"), sel("unhide"));
  2835. }
  2836. id wdg = objc_msgSend_id(window, sel("delegate"));
  2837. objc_msgSend_void(wdg, sel("release"));
  2838. objc_msgSend_void((id)win->gl.glContext, sel("release"));
  2839. objc_msgSend_void(window, sel("release"));
  2840. }
  2841. free(bmp->pix);
  2842. free(bmp);
  2843. }
  2844. uint8_t _tigrKeyFromOSX(uint16_t key) {
  2845. // from Carbon HIToolbox/Events.h
  2846. enum {
  2847. kVK_ANSI_A = 0x00,
  2848. kVK_ANSI_S = 0x01,
  2849. kVK_ANSI_D = 0x02,
  2850. kVK_ANSI_F = 0x03,
  2851. kVK_ANSI_H = 0x04,
  2852. kVK_ANSI_G = 0x05,
  2853. kVK_ANSI_Z = 0x06,
  2854. kVK_ANSI_X = 0x07,
  2855. kVK_ANSI_C = 0x08,
  2856. kVK_ANSI_V = 0x09,
  2857. kVK_ANSI_B = 0x0B,
  2858. kVK_ANSI_Q = 0x0C,
  2859. kVK_ANSI_W = 0x0D,
  2860. kVK_ANSI_E = 0x0E,
  2861. kVK_ANSI_R = 0x0F,
  2862. kVK_ANSI_Y = 0x10,
  2863. kVK_ANSI_T = 0x11,
  2864. kVK_ANSI_1 = 0x12,
  2865. kVK_ANSI_2 = 0x13,
  2866. kVK_ANSI_3 = 0x14,
  2867. kVK_ANSI_4 = 0x15,
  2868. kVK_ANSI_6 = 0x16,
  2869. kVK_ANSI_5 = 0x17,
  2870. kVK_ANSI_Equal = 0x18,
  2871. kVK_ANSI_9 = 0x19,
  2872. kVK_ANSI_7 = 0x1A,
  2873. kVK_ANSI_Minus = 0x1B,
  2874. kVK_ANSI_8 = 0x1C,
  2875. kVK_ANSI_0 = 0x1D,
  2876. kVK_ANSI_RightBracket = 0x1E,
  2877. kVK_ANSI_O = 0x1F,
  2878. kVK_ANSI_U = 0x20,
  2879. kVK_ANSI_LeftBracket = 0x21,
  2880. kVK_ANSI_I = 0x22,
  2881. kVK_ANSI_P = 0x23,
  2882. kVK_ANSI_L = 0x25,
  2883. kVK_ANSI_J = 0x26,
  2884. kVK_ANSI_Quote = 0x27,
  2885. kVK_ANSI_K = 0x28,
  2886. kVK_ANSI_Semicolon = 0x29,
  2887. kVK_ANSI_Backslash = 0x2A,
  2888. kVK_ANSI_Comma = 0x2B,
  2889. kVK_ANSI_Slash = 0x2C,
  2890. kVK_ANSI_N = 0x2D,
  2891. kVK_ANSI_M = 0x2E,
  2892. kVK_ANSI_Period = 0x2F,
  2893. kVK_ANSI_Grave = 0x32,
  2894. kVK_ANSI_KeypadDecimal = 0x41,
  2895. kVK_ANSI_KeypadMultiply = 0x43,
  2896. kVK_ANSI_KeypadPlus = 0x45,
  2897. kVK_ANSI_KeypadClear = 0x47,
  2898. kVK_ANSI_KeypadDivide = 0x4B,
  2899. kVK_ANSI_KeypadEnter = 0x4C,
  2900. kVK_ANSI_KeypadMinus = 0x4E,
  2901. kVK_ANSI_KeypadEquals = 0x51,
  2902. kVK_ANSI_Keypad0 = 0x52,
  2903. kVK_ANSI_Keypad1 = 0x53,
  2904. kVK_ANSI_Keypad2 = 0x54,
  2905. kVK_ANSI_Keypad3 = 0x55,
  2906. kVK_ANSI_Keypad4 = 0x56,
  2907. kVK_ANSI_Keypad5 = 0x57,
  2908. kVK_ANSI_Keypad6 = 0x58,
  2909. kVK_ANSI_Keypad7 = 0x59,
  2910. kVK_ANSI_Keypad8 = 0x5B,
  2911. kVK_ANSI_Keypad9 = 0x5C,
  2912. kVK_Return = 0x24,
  2913. kVK_Tab = 0x30,
  2914. kVK_Space = 0x31,
  2915. kVK_Delete = 0x33,
  2916. kVK_Escape = 0x35,
  2917. kVK_Command = 0x37,
  2918. kVK_Shift = 0x38,
  2919. kVK_CapsLock = 0x39,
  2920. kVK_Option = 0x3A,
  2921. kVK_Control = 0x3B,
  2922. kVK_RightShift = 0x3C,
  2923. kVK_RightOption = 0x3D,
  2924. kVK_RightControl = 0x3E,
  2925. kVK_Function = 0x3F,
  2926. kVK_F17 = 0x40,
  2927. kVK_VolumeUp = 0x48,
  2928. kVK_VolumeDown = 0x49,
  2929. kVK_Mute = 0x4A,
  2930. kVK_F18 = 0x4F,
  2931. kVK_F19 = 0x50,
  2932. kVK_F20 = 0x5A,
  2933. kVK_F5 = 0x60,
  2934. kVK_F6 = 0x61,
  2935. kVK_F7 = 0x62,
  2936. kVK_F3 = 0x63,
  2937. kVK_F8 = 0x64,
  2938. kVK_F9 = 0x65,
  2939. kVK_F11 = 0x67,
  2940. kVK_F13 = 0x69,
  2941. kVK_F16 = 0x6A,
  2942. kVK_F14 = 0x6B,
  2943. kVK_F10 = 0x6D,
  2944. kVK_F12 = 0x6F,
  2945. kVK_F15 = 0x71,
  2946. kVK_Help = 0x72,
  2947. kVK_Home = 0x73,
  2948. kVK_PageUp = 0x74,
  2949. kVK_ForwardDelete = 0x75,
  2950. kVK_F4 = 0x76,
  2951. kVK_End = 0x77,
  2952. kVK_F2 = 0x78,
  2953. kVK_PageDown = 0x79,
  2954. kVK_F1 = 0x7A,
  2955. kVK_LeftArrow = 0x7B,
  2956. kVK_RightArrow = 0x7C,
  2957. kVK_DownArrow = 0x7D,
  2958. kVK_UpArrow = 0x7E
  2959. };
  2960. switch (key) {
  2961. case kVK_ANSI_Q:
  2962. return 'Q';
  2963. case kVK_ANSI_W:
  2964. return 'W';
  2965. case kVK_ANSI_E:
  2966. return 'E';
  2967. case kVK_ANSI_R:
  2968. return 'R';
  2969. case kVK_ANSI_T:
  2970. return 'T';
  2971. case kVK_ANSI_Y:
  2972. return 'Y';
  2973. case kVK_ANSI_U:
  2974. return 'U';
  2975. case kVK_ANSI_I:
  2976. return 'I';
  2977. case kVK_ANSI_O:
  2978. return 'O';
  2979. case kVK_ANSI_P:
  2980. return 'P';
  2981. case kVK_ANSI_A:
  2982. return 'A';
  2983. case kVK_ANSI_S:
  2984. return 'S';
  2985. case kVK_ANSI_D:
  2986. return 'D';
  2987. case kVK_ANSI_F:
  2988. return 'F';
  2989. case kVK_ANSI_G:
  2990. return 'G';
  2991. case kVK_ANSI_H:
  2992. return 'H';
  2993. case kVK_ANSI_J:
  2994. return 'J';
  2995. case kVK_ANSI_K:
  2996. return 'K';
  2997. case kVK_ANSI_L:
  2998. return 'L';
  2999. case kVK_ANSI_Z:
  3000. return 'Z';
  3001. case kVK_ANSI_X:
  3002. return 'X';
  3003. case kVK_ANSI_C:
  3004. return 'C';
  3005. case kVK_ANSI_V:
  3006. return 'V';
  3007. case kVK_ANSI_B:
  3008. return 'B';
  3009. case kVK_ANSI_N:
  3010. return 'N';
  3011. case kVK_ANSI_M:
  3012. return 'M';
  3013. case kVK_ANSI_0:
  3014. return '0';
  3015. case kVK_ANSI_1:
  3016. return '1';
  3017. case kVK_ANSI_2:
  3018. return '2';
  3019. case kVK_ANSI_3:
  3020. return '3';
  3021. case kVK_ANSI_4:
  3022. return '4';
  3023. case kVK_ANSI_5:
  3024. return '5';
  3025. case kVK_ANSI_6:
  3026. return '6';
  3027. case kVK_ANSI_7:
  3028. return '7';
  3029. case kVK_ANSI_8:
  3030. return '8';
  3031. case kVK_ANSI_9:
  3032. return '9';
  3033. case kVK_ANSI_Keypad0:
  3034. return TK_PAD0;
  3035. case kVK_ANSI_Keypad1:
  3036. return TK_PAD1;
  3037. case kVK_ANSI_Keypad2:
  3038. return TK_PAD2;
  3039. case kVK_ANSI_Keypad3:
  3040. return TK_PAD3;
  3041. case kVK_ANSI_Keypad4:
  3042. return TK_PAD4;
  3043. case kVK_ANSI_Keypad5:
  3044. return TK_PAD5;
  3045. case kVK_ANSI_Keypad6:
  3046. return TK_PAD6;
  3047. case kVK_ANSI_Keypad7:
  3048. return TK_PAD7;
  3049. case kVK_ANSI_Keypad8:
  3050. return TK_PAD8;
  3051. case kVK_ANSI_Keypad9:
  3052. return TK_PAD9;
  3053. case kVK_ANSI_KeypadMultiply:
  3054. return TK_PADMUL;
  3055. case kVK_ANSI_KeypadPlus:
  3056. return TK_PADADD;
  3057. case kVK_ANSI_KeypadEnter:
  3058. return TK_PADENTER;
  3059. case kVK_ANSI_KeypadMinus:
  3060. return TK_PADSUB;
  3061. case kVK_ANSI_KeypadDecimal:
  3062. return TK_PADDOT;
  3063. case kVK_ANSI_KeypadDivide:
  3064. return TK_PADDIV;
  3065. case kVK_F1:
  3066. return TK_F1;
  3067. case kVK_F2:
  3068. return TK_F2;
  3069. case kVK_F3:
  3070. return TK_F3;
  3071. case kVK_F4:
  3072. return TK_F4;
  3073. case kVK_F5:
  3074. return TK_F5;
  3075. case kVK_F6:
  3076. return TK_F6;
  3077. case kVK_F7:
  3078. return TK_F7;
  3079. case kVK_F8:
  3080. return TK_F8;
  3081. case kVK_F9:
  3082. return TK_F9;
  3083. case kVK_F10:
  3084. return TK_F10;
  3085. case kVK_F11:
  3086. return TK_F11;
  3087. case kVK_F12:
  3088. return TK_F12;
  3089. case kVK_Shift:
  3090. return TK_LSHIFT;
  3091. case kVK_Control:
  3092. return TK_LCONTROL;
  3093. case kVK_Option:
  3094. return TK_LALT;
  3095. case kVK_CapsLock:
  3096. return TK_CAPSLOCK;
  3097. case kVK_Command:
  3098. return TK_LWIN;
  3099. case kVK_Command - 1:
  3100. return TK_RWIN;
  3101. case kVK_RightShift:
  3102. return TK_RSHIFT;
  3103. case kVK_RightControl:
  3104. return TK_RCONTROL;
  3105. case kVK_RightOption:
  3106. return TK_RALT;
  3107. case kVK_Delete:
  3108. return TK_BACKSPACE;
  3109. case kVK_Tab:
  3110. return TK_TAB;
  3111. case kVK_Return:
  3112. return TK_RETURN;
  3113. case kVK_Escape:
  3114. return TK_ESCAPE;
  3115. case kVK_Space:
  3116. return TK_SPACE;
  3117. case kVK_PageUp:
  3118. return TK_PAGEUP;
  3119. case kVK_PageDown:
  3120. return TK_PAGEDN;
  3121. case kVK_End:
  3122. return TK_END;
  3123. case kVK_Home:
  3124. return TK_HOME;
  3125. case kVK_LeftArrow:
  3126. return TK_LEFT;
  3127. case kVK_UpArrow:
  3128. return TK_UP;
  3129. case kVK_RightArrow:
  3130. return TK_RIGHT;
  3131. case kVK_DownArrow:
  3132. return TK_DOWN;
  3133. case kVK_Help:
  3134. return TK_INSERT;
  3135. case kVK_ForwardDelete:
  3136. return TK_DELETE;
  3137. case kVK_F14:
  3138. return TK_SCROLL;
  3139. case kVK_F15:
  3140. return TK_PAUSE;
  3141. case kVK_ANSI_KeypadClear:
  3142. return TK_NUMLOCK;
  3143. case kVK_ANSI_Semicolon:
  3144. return TK_SEMICOLON;
  3145. case kVK_ANSI_Equal:
  3146. return TK_EQUALS;
  3147. case kVK_ANSI_Comma:
  3148. return TK_COMMA;
  3149. case kVK_ANSI_Minus:
  3150. return TK_MINUS;
  3151. case kVK_ANSI_Slash:
  3152. return TK_SLASH;
  3153. case kVK_ANSI_Backslash:
  3154. return TK_BACKSLASH;
  3155. case kVK_ANSI_Grave:
  3156. return TK_BACKTICK;
  3157. case kVK_ANSI_Quote:
  3158. return TK_TICK;
  3159. case kVK_ANSI_LeftBracket:
  3160. return TK_LSQUARE;
  3161. case kVK_ANSI_RightBracket:
  3162. return TK_RSQUARE;
  3163. case kVK_ANSI_Period:
  3164. return TK_DOT;
  3165. default:
  3166. return 0;
  3167. }
  3168. }
  3169. void _tigrOnCocoaEvent(id event, id window) {
  3170. if (!event)
  3171. return;
  3172. TigrInternal* win = _tigrInternalFromWindow(window);
  3173. if (!win) // just pipe the event
  3174. {
  3175. objc_msgSend_void_id(NSApp, sel("sendEvent:"), event);
  3176. return;
  3177. }
  3178. NSUInteger eventType = objc_msgSend_t(NSUInteger)(event, sel("type"));
  3179. switch (eventType) {
  3180. case 1: // NSLeftMouseDown
  3181. if (win->mouseInView) {
  3182. win->mouseButtons |= 1;
  3183. }
  3184. break;
  3185. case 2: // NSLeftMouseUp
  3186. win->mouseButtons &= ~1;
  3187. break;
  3188. case 3: // NSRightMouseDown
  3189. if (win->mouseInView) {
  3190. win->mouseButtons |= 2;
  3191. }
  3192. break;
  3193. case 4: // NSRightMouseUp
  3194. win->mouseButtons &= ~2;
  3195. break;
  3196. case 25: // NSOtherMouseDown
  3197. {
  3198. // number == 2 is a middle button
  3199. NSInteger number = objc_msgSend_t(NSInteger)(event, sel("buttonNumber"));
  3200. if (number == 2 && win->mouseInView) {
  3201. win->mouseButtons |= 4;
  3202. }
  3203. break;
  3204. }
  3205. case 26: // NSOtherMouseUp
  3206. {
  3207. NSInteger number = objc_msgSend_t(NSInteger)(event, sel("buttonNumber"));
  3208. if (number == 2)
  3209. win->mouseButtons &= ~4;
  3210. break;
  3211. }
  3212. case 22: // NSScrollWheel
  3213. {
  3214. CGFloat deltaX = objc_msgSend_t(CGFloat)(event, sel("deltaX"));
  3215. win->scrollDeltaX += deltaX;
  3216. CGFloat deltaY = objc_msgSend_t(CGFloat)(event, sel("deltaY"));
  3217. win->scrollDeltaY += deltaY;
  3218. break;
  3219. }
  3220. case 12: // NSFlagsChanged
  3221. {
  3222. NSUInteger modifiers = objc_msgSend_t(NSUInteger)(event, sel("modifierFlags"));
  3223. // based on NSEventModifierFlags and
  3224. // NSDeviceIndependentModifierFlagsMask
  3225. struct {
  3226. union {
  3227. struct {
  3228. uint8_t alpha_shift : 1;
  3229. uint8_t shift : 1;
  3230. uint8_t control : 1;
  3231. uint8_t alternate : 1;
  3232. uint8_t command : 1;
  3233. uint8_t numeric_pad : 1;
  3234. uint8_t help : 1;
  3235. uint8_t function : 1;
  3236. };
  3237. uint8_t mask;
  3238. };
  3239. } keys;
  3240. keys.mask = (modifiers & 0xffff0000UL) >> 16;
  3241. // TODO L,R variation of keys?
  3242. win->keys[TK_CONTROL] = keys.alpha_shift;
  3243. win->keys[TK_SHIFT] = keys.shift;
  3244. win->keys[TK_CONTROL] = keys.control;
  3245. win->keys[TK_ALT] = keys.alternate;
  3246. win->keys[TK_LWIN] = keys.command;
  3247. win->keys[TK_RWIN] = keys.command;
  3248. break;
  3249. }
  3250. case 10: // NSKeyDown
  3251. {
  3252. uint16_t keyCode = objc_msgSend_t(unsigned short)(event, sel("keyCode"));
  3253. int tigrKey = _tigrKeyFromOSX(keyCode);
  3254. // Ignore keyboard repeats
  3255. if (!win->keys[tigrKey]) {
  3256. win->keys[tigrKey] = 1;
  3257. id inputText = objc_msgSend_id(event, sel("characters"));
  3258. const char* inputTextUTF8 = objc_msgSend_t(const char*)(inputText, sel("UTF8String"));
  3259. int decoded = 0;
  3260. tigrDecodeUTF8(inputTextUTF8, &decoded);
  3261. if (decoded < 0xe000 || decoded > 0xf8ff) {
  3262. win->lastChar = decoded;
  3263. }
  3264. }
  3265. // Pass through cmd+key
  3266. if (win->keys[TK_LWIN]) {
  3267. break;
  3268. }
  3269. return;
  3270. }
  3271. case 11: // NSKeyUp
  3272. {
  3273. uint16_t keyCode = objc_msgSend_t(unsigned short)(event, sel("keyCode"));
  3274. win->keys[_tigrKeyFromOSX(keyCode)] = 0;
  3275. return;
  3276. }
  3277. default:
  3278. break;
  3279. }
  3280. objc_msgSend_void_id(NSApp, sel("sendEvent:"), event);
  3281. }
  3282. void tigrUpdate(Tigr* bmp) {
  3283. popPool(autoreleasePool);
  3284. autoreleasePool = pushPool();
  3285. TigrInternal* win;
  3286. id openGLContext;
  3287. id window;
  3288. win = tigrInternal(bmp);
  3289. window = (id)bmp->handle;
  3290. openGLContext = (id)win->gl.glContext;
  3291. if (terminated || _tigrIsWindowClosed(window)) {
  3292. return;
  3293. }
  3294. id keyWindow = objc_msgSend_id(NSApp, sel("keyWindow"));
  3295. unsigned long long eventMask = NSAllEventMask;
  3296. if (keyWindow == window) {
  3297. memcpy(win->prev, win->keys, 256);
  3298. } else {
  3299. eventMask &= ~(NSKeyDownMask | NSKeyUpMask);
  3300. }
  3301. win->scrollDeltaX = 0;
  3302. win->scrollDeltaY = 0;
  3303. id event = 0;
  3304. BOOL visible = 0;
  3305. double now = _currentMediaTime();
  3306. double passed = now - _tigrTimestamp;
  3307. do {
  3308. event = objc_msgSend_t(id, NSUInteger, id, id, BOOL)(
  3309. NSApp, sel("nextEventMatchingMask:untilDate:inMode:dequeue:"), eventMask, nil, NSDefaultRunLoopMode, YES);
  3310. if (event != 0) {
  3311. _tigrOnCocoaEvent(event, window);
  3312. } else {
  3313. visible = _tigrIsWindowVisible(window);
  3314. }
  3315. } while (event != 0 || !visible);
  3316. // The event processing loop above blocks during resize, which causes updates to freeze
  3317. // but real time keeps ticking. We pretend that the event processing took no time
  3318. // to avoid huge jumps in tigrTime.
  3319. if (_tigrTimestamp != 0) {
  3320. _tigrTimestamp = _currentMediaTime() - passed;
  3321. }
  3322. objc_msgSend_void(NSApp, sel("updateWindows"));
  3323. objc_msgSend_void(openGLContext, sel("update"));
  3324. tigrGAPIBegin(bmp);
  3325. NSSize windowSize = _tigrContentBackingSize(window);
  3326. if (win->flags & TIGR_AUTO)
  3327. tigrResize(bmp, windowSize.width / win->scale, windowSize.height / win->scale);
  3328. else
  3329. win->scale = tigrEnforceScale(tigrCalcScale(bmp->w, bmp->h, windowSize.width, windowSize.height), win->flags);
  3330. tigrPosition(bmp, win->scale, windowSize.width, windowSize.height, win->pos);
  3331. tigrGAPIPresent(bmp, windowSize.width, windowSize.height);
  3332. objc_msgSend_void(openGLContext, sel("flushBuffer"));
  3333. tigrGAPIEnd(bmp);
  3334. id runLoop = objc_msgSend_id(class("NSRunLoop"), sel("currentRunLoop"));
  3335. id until = objc_msgSend_t(id, float)(class("NSDate"), sel("dateWithTimeIntervalSinceNow:"), 0.005f);
  3336. double lastFrameTime = win->frameTime;
  3337. static const double cap = 1.0 / 60;
  3338. while (win->frameTime <= lastFrameTime) {
  3339. // Run the event loop for 5ms at a time..
  3340. objc_msgSend_t(void, id, id)(runLoop, sel("runMode:beforeDate:"), NSDefaultRunLoopMode, until);
  3341. // ..until we get a frame callback..
  3342. if (win->frameTime > lastFrameTime) {
  3343. break;
  3344. }
  3345. double now = _currentMediaTime();
  3346. double passed = now - lastFrameTime;
  3347. // ..or it's time to cap the wait at 60 fps
  3348. if (passed > cap) {
  3349. win->frameTime = now;
  3350. break;
  3351. }
  3352. }
  3353. }
  3354. int tigrGAPIBegin(Tigr* bmp) {
  3355. TigrInternal* win = tigrInternal(bmp);
  3356. objc_msgSend_void((id)win->gl.glContext, sel("makeCurrentContext"));
  3357. return 0;
  3358. }
  3359. int tigrGAPIEnd(Tigr* bmp) {
  3360. (void)bmp;
  3361. objc_msgSend_void(class("NSOpenGLContext"), sel("clearCurrentContext"));
  3362. return 0;
  3363. }
  3364. int tigrClosed(Tigr* bmp) {
  3365. return (terminated || _tigrIsWindowClosed((id)bmp->handle)) ? 1 : 0;
  3366. }
  3367. void tigrMouse(Tigr* bmp, int* x, int* y, int* buttons) {
  3368. TigrInternal* win;
  3369. id window;
  3370. win = tigrInternal(bmp);
  3371. window = (id)bmp->handle;
  3372. id windowContentView = objc_msgSend_id(window, sel("contentView"));
  3373. NSRect adjustFrame = objc_msgSend_stret_t(NSRect)(windowContentView, sel("frame"));
  3374. // NSPoint is small enough to fit a register, so no need for
  3375. // objc_msgSend_stret
  3376. NSPoint p = objc_msgSend_t(NSPoint)(window, sel("mouseLocationOutsideOfEventStream"));
  3377. // map input to content view rect
  3378. if (p.x < 0)
  3379. p.x = 0;
  3380. else if (p.x > adjustFrame.size.width)
  3381. p.x = adjustFrame.size.width;
  3382. if (p.y < 0)
  3383. p.y = 0;
  3384. else if (p.y > adjustFrame.size.height)
  3385. p.y = adjustFrame.size.height;
  3386. // map input to pixels
  3387. NSRect r = { p, { 0, 0 } };
  3388. r = objc_msgSend_stret_t(NSRect, NSRect)(windowContentView, sel("convertRectToBacking:"), r);
  3389. p = r.origin;
  3390. p.x = (p.x - win->pos[0]) / win->scale;
  3391. p.y = bmp->h - (p.y - win->pos[1]) / win->scale;
  3392. if (x)
  3393. *x = p.x;
  3394. if (y)
  3395. *y = p.y;
  3396. if (buttons) {
  3397. id keyWindow = objc_msgSend_id(NSApp, sel("keyWindow"));
  3398. *buttons = keyWindow != bmp->handle ? 0 : win->mouseButtons;
  3399. }
  3400. }
  3401. int tigrTouch(Tigr* bmp, TigrTouchPoint* points, int maxPoints) {
  3402. int buttons = 0;
  3403. if (maxPoints > 0) {
  3404. tigrMouse(bmp, &points[0].x, &points[1].y, &buttons);
  3405. }
  3406. return buttons ? 1 : 0;
  3407. }
  3408. void tigrScrollWheel(Tigr* bmp, float* x, float* y) {
  3409. TigrInternal* win;
  3410. win = tigrInternal(bmp);
  3411. if (x) {
  3412. *x = win->scrollDeltaX;
  3413. }
  3414. if (y) {
  3415. *y = win->scrollDeltaY;
  3416. }
  3417. }
  3418. int tigrKeyDown(Tigr* bmp, int key) {
  3419. TigrInternal* win;
  3420. assert(key < 256);
  3421. win = tigrInternal(bmp);
  3422. return (win->keys[key] != 0) && (win->prev[key] == 0);
  3423. }
  3424. int tigrKeyHeld(Tigr* bmp, int key) {
  3425. TigrInternal* win;
  3426. assert(key < 256);
  3427. win = tigrInternal(bmp);
  3428. return win->keys[key];
  3429. }
  3430. int tigrReadChar(Tigr* bmp) {
  3431. TigrInternal* win = tigrInternal(bmp);
  3432. int c = win->lastChar;
  3433. win->lastChar = 0;
  3434. return c;
  3435. }
  3436. float tigrTime(void) {
  3437. double elapsed = 0;
  3438. double now = _currentMediaTime();
  3439. if (_tigrTimestamp != 0) {
  3440. elapsed = now - _tigrTimestamp;
  3441. }
  3442. _tigrTimestamp = now;
  3443. return (float)elapsed;
  3444. }
  3445. #endif // __MACOS__
  3446. #endif // #ifndef TIGR_HEADLESS
  3447. //////// End of inlined file: tigr_osx.c ////////
  3448. //////// Start of inlined file: tigr_ios.c ////////
  3449. #ifndef TIGR_HEADLESS
  3450. //#include "tigr_internal.h"
  3451. //#include "tigr_objc.h"
  3452. #ifdef __IOS__
  3453. #include <CoreGraphics/CoreGraphics.h>
  3454. #include <objc/message.h>
  3455. #include <objc/objc.h>
  3456. #include <objc/runtime.h>
  3457. #include <dispatch/dispatch.h>
  3458. #include <os/log.h>
  3459. #include <time.h>
  3460. #include <stdatomic.h>
  3461. id makeNSString(const char* str) {
  3462. return objc_msgSend_t(id, const char*)(class("NSString"), sel("stringWithUTF8String:"), str);
  3463. }
  3464. id joinNSStrings(id a, id b) {
  3465. return objc_msgSend_t(id, id)(a, sel("stringByAppendingString:"), b);
  3466. }
  3467. const char* UTF8StringFromNSString(id a) {
  3468. return objc_msgSend_t(const char*)(a, sel("UTF8String"));
  3469. }
  3470. extern id UIApplication;
  3471. static int NSQualityOfServiceUserInteractive = 0x21;
  3472. typedef struct {
  3473. TigrTouchPoint points[MAX_TOUCH_POINTS];
  3474. int numPoints;
  3475. } InputState;
  3476. typedef struct {
  3477. int keyCode;
  3478. int codePoint;
  3479. } KeyEvent;
  3480. enum {
  3481. KBD_HIDDEN = 0,
  3482. KBD_SHOWREQ,
  3483. KBD_HIDEREQ,
  3484. KBD_SHOWN,
  3485. };
  3486. /// Global state
  3487. static struct {
  3488. InputState inputState;
  3489. id viewController;
  3490. id view;
  3491. id context;
  3492. id frameCondition;
  3493. int screenW;
  3494. int screenH;
  3495. double scaleFactor;
  3496. double timeSinceLastDraw;
  3497. int renderReadFd;
  3498. int mainWriteFd;
  3499. _Atomic(int) keyboardState;
  3500. } gState = {
  3501. .inputState = {
  3502. .numPoints = 0,
  3503. },
  3504. .viewController = 0,
  3505. .view = 0,
  3506. .context = 0,
  3507. .frameCondition = 0,
  3508. .screenW = 0,
  3509. .screenH = 0,
  3510. .scaleFactor = 1,
  3511. .timeSinceLastDraw = 0,
  3512. .renderReadFd = 0,
  3513. .mainWriteFd = 0,
  3514. .keyboardState = ATOMIC_VAR_INIT(KBD_HIDDEN),
  3515. };
  3516. typedef enum {
  3517. SET_INPUT,
  3518. KEY_EVENT,
  3519. } TigrMessage;
  3520. typedef struct TigrMessageData {
  3521. TigrMessage message;
  3522. union {
  3523. InputState inputState;
  3524. KeyEvent keyEvent;
  3525. };
  3526. } TigrMessageData;
  3527. static id autoreleasePool = NULL;
  3528. void writeToRenderThread(const TigrMessageData* message) {
  3529. if (write(gState.mainWriteFd, message, sizeof(TigrMessageData)) != sizeof(TigrMessageData)) {
  3530. os_log_error(OS_LOG_DEFAULT, "Failed to write message to render thread: %{public}s", strerror(errno));
  3531. }
  3532. }
  3533. int readFromMainThread(TigrMessageData* message) {
  3534. int result = read(gState.renderReadFd, message, sizeof(TigrMessageData));
  3535. if (result == -1 && errno == EAGAIN) {
  3536. return 0;
  3537. }
  3538. if (result != sizeof(TigrMessageData)) {
  3539. os_log_error(OS_LOG_DEFAULT, "Failed to read message from main thread: %{public}s", strerror(errno));
  3540. return 0;
  3541. }
  3542. return 1;
  3543. }
  3544. void viewWillTransitionToSize(id self, SEL _sel, CGSize size, id transitionCoordinator) {
  3545. // No animation, just set them
  3546. gState.screenW = size.width * gState.scaleFactor;
  3547. gState.screenH = size.height * gState.scaleFactor;
  3548. struct objc_super super = {
  3549. self,
  3550. objc_getClass("GLKViewController"),
  3551. };
  3552. objc_msgSendSuper_t(void, CGSize, id)(&super, _sel, size, transitionCoordinator);
  3553. }
  3554. BOOL prefersStatusBarHidden(id self, SEL _sel) {
  3555. return YES;
  3556. }
  3557. BOOL hasText(id self, SEL _sel) {
  3558. return NO;
  3559. }
  3560. void tigrShowKeyboard(int show) {
  3561. int expected = show ? KBD_HIDDEN : KBD_SHOWN;
  3562. int desired = show ? KBD_SHOWREQ : KBD_HIDEREQ;
  3563. atomic_compare_exchange_weak(&gState.keyboardState, &expected, desired);
  3564. }
  3565. void insertText(id self, SEL _sel, id text) {
  3566. const char* inserted = UTF8StringFromNSString(text);
  3567. int codePoint = 0;
  3568. do {
  3569. inserted = tigrDecodeUTF8(inserted, &codePoint);
  3570. if (codePoint != 0) {
  3571. KeyEvent event;
  3572. event.codePoint = codePoint;
  3573. event.keyCode = (codePoint < 128) ? codePoint : 0;
  3574. TigrMessageData message = {
  3575. .message = KEY_EVENT,
  3576. .keyEvent = event,
  3577. };
  3578. writeToRenderThread(&message);
  3579. }
  3580. } while (*inserted != 0);
  3581. }
  3582. void deleteBackward(id self, SEL _sel) {
  3583. KeyEvent event;
  3584. event.codePoint = 0;
  3585. event.keyCode = 8; // BS
  3586. TigrMessageData message = { .message = KEY_EVENT,
  3587. .keyEvent = {
  3588. .codePoint = 0,
  3589. .keyCode = 8,
  3590. } };
  3591. writeToRenderThread(&message);
  3592. }
  3593. BOOL canBecomeFirstResponder(id self, SEL _sel) {
  3594. return YES;
  3595. }
  3596. BOOL canResignFirstResponder(id self, SEL _sel) {
  3597. return YES;
  3598. }
  3599. enum RenderState { SWAPPED = 5150, RENDERED };
  3600. BOOL didFinishLaunchingWithOptions(id self, SEL _sel, id application, id options) {
  3601. id screen = objc_msgSend_id(class("UIScreen"), sel("mainScreen"));
  3602. CGRect bounds = objc_msgSend_t(CGRect)(screen, sel("bounds"));
  3603. CGSize size = bounds.size;
  3604. id window = objc_alloc("UIWindow");
  3605. window = objc_msgSend_t(id, CGRect)(window, sel("initWithFrame:"), bounds);
  3606. Class ViewController = makeClass("TigrViewController", "GLKViewController");
  3607. addMethod(ViewController, "viewWillTransitionToSize:withTransitionCoordinator:", viewWillTransitionToSize,
  3608. "v@:{CGSize}@");
  3609. addMethod(ViewController, "prefersStatusBarHidden", prefersStatusBarHidden, "c@:");
  3610. id vc = objc_msgSend_t(id)((id)ViewController, sel("alloc"));
  3611. vc = objc_msgSend_id(vc, sel("init"));
  3612. gState.viewController = vc;
  3613. objc_msgSend_t(void, int)(vc, sel("setPreferredFramesPerSecond:"), 60);
  3614. int framesPerSecond = objc_msgSend_t(int)(vc, sel("framesPerSecond"));
  3615. id context = objc_alloc("EAGLContext");
  3616. static int kEAGLRenderingAPIOpenGLES3 = 3;
  3617. context = objc_msgSend_t(id, int)(context, sel("initWithAPI:"), kEAGLRenderingAPIOpenGLES3);
  3618. gState.context = context;
  3619. Class View = makeClass("TigrView", "GLKView");
  3620. addMethod(View, "insertText:", insertText, "v@:@");
  3621. addMethod(View, "deleteBackward", deleteBackward, "v@:");
  3622. addMethod(View, "hasText", hasText, "c@:");
  3623. addMethod(View, "canBecomeFirstResponder", canBecomeFirstResponder, "c@:");
  3624. addMethod(View, "canResignFirstResponder", canResignFirstResponder, "c@:");
  3625. Protocol* UIKeyInput = objc_getProtocol("UIKeyInput");
  3626. class_addProtocol(View, UIKeyInput);
  3627. id view = objc_msgSend_id((id)View, sel("alloc"));
  3628. view = objc_msgSend_t(id, CGRect, id)(view, sel("initWithFrame:context:"), bounds, context);
  3629. gState.view = view;
  3630. objc_msgSend_t(void, BOOL)(view, sel("setMultipleTouchEnabled:"), YES);
  3631. objc_msgSend_t(void, id)(view, sel("setDelegate:"), self);
  3632. objc_msgSend_t(void, id)(vc, sel("setView:"), view);
  3633. objc_msgSend_t(void, id)(vc, sel("setDelegate:"), self);
  3634. objc_msgSend_t(void, id)(window, sel("setRootViewController:"), vc);
  3635. objc_msgSend_t(void)(window, sel("makeKeyAndVisible"));
  3636. gState.scaleFactor = objc_msgSend_t(double)(view, sel("contentScaleFactor"));
  3637. gState.screenW = size.width * gState.scaleFactor;
  3638. gState.screenH = size.height * gState.scaleFactor;
  3639. gState.frameCondition = objc_msgSend_t(id, int)(objc_alloc("NSConditionLock"), sel("initWithCondition:"), RENDERED);
  3640. objc_msgSend_t(void, int)(gState.frameCondition, sel("lockWhenCondition:"), RENDERED);
  3641. id renderThread = objc_msgSend_t(id, id, SEL, id)(objc_alloc("NSThread"), sel("initWithTarget:selector:object:"),
  3642. self, sel("renderMain"), NULL);
  3643. objc_msgSend_t(void, int)(renderThread, sel("setQualityOfService:"), NSQualityOfServiceUserInteractive);
  3644. objc_msgSend_t(void, id)(renderThread, sel("setName:"), makeNSString("Tigr Render Thread"));
  3645. objc_msgSend_void(renderThread, sel("start"));
  3646. return YES;
  3647. }
  3648. void waitForFrame() {
  3649. objc_msgSend_t(void, id)(class("EAGLContext"), sel("setCurrentContext:"), 0);
  3650. objc_msgSend_t(void, int)(gState.frameCondition, sel("unlockWithCondition:"), RENDERED);
  3651. objc_msgSend_t(void, int)(gState.frameCondition, sel("lockWhenCondition:"), SWAPPED);
  3652. objc_msgSend_t(void, id)(class("EAGLContext"), sel("setCurrentContext:"), gState.context);
  3653. }
  3654. void processKeyboardRequest() {
  3655. int showReq = KBD_SHOWREQ;
  3656. int hideReq = KBD_HIDEREQ;
  3657. if (atomic_compare_exchange_weak(&gState.keyboardState, &showReq, KBD_SHOWN)) {
  3658. objc_msgSend_t(BOOL)(gState.view, sel("becomeFirstResponder"));
  3659. } else if (atomic_compare_exchange_weak(&gState.keyboardState, &hideReq, KBD_HIDDEN)) {
  3660. objc_msgSend_t(BOOL)(gState.view, sel("resignFirstResponder"));
  3661. }
  3662. }
  3663. void drawInRect(id _self, SEL _sel, id view, CGRect rect) {
  3664. gState.timeSinceLastDraw = objc_msgSend_t(double)(gState.viewController, sel("timeSinceLastDraw"));
  3665. objc_msgSend_t(void, int)(gState.frameCondition, sel("unlockWithCondition:"), SWAPPED);
  3666. objc_msgSend_t(void, int)(gState.frameCondition, sel("lockWhenCondition:"), RENDERED);
  3667. objc_msgSend_t(void, id)(class("EAGLContext"), sel("setCurrentContext:"), gState.context);
  3668. processKeyboardRequest();
  3669. }
  3670. extern void tigrMain();
  3671. void renderMain(id _self, SEL _sel) {
  3672. objc_msgSend_t(void, int)(gState.frameCondition, sel("lockWhenCondition:"), SWAPPED);
  3673. objc_msgSend_t(void, id)(class("EAGLContext"), sel("setCurrentContext:"), gState.context);
  3674. tigrMain();
  3675. }
  3676. enum {
  3677. UITouchPhaseBegan,
  3678. UITouchPhaseMoved,
  3679. UITouchPhaseStationary,
  3680. UITouchPhaseEnded,
  3681. UITouchPhaseCancelled,
  3682. };
  3683. void touches(id self, SEL sel, id touches, id event) {
  3684. id allTouches = objc_msgSend_t(id)(event, sel("allTouches"));
  3685. id enumerator = objc_msgSend_t(id)(allTouches, sel("objectEnumerator"));
  3686. id touch = 0;
  3687. InputState input = {
  3688. .numPoints = 0,
  3689. };
  3690. while ((touch = objc_msgSend_t(id)(enumerator, sel("nextObject")))) {
  3691. CGPoint location = objc_msgSend_t(CGPoint, id)(touch, sel("locationInView:"), NULL);
  3692. int phase = objc_msgSend_t(int)(touch, sel("phase"));
  3693. switch (phase) {
  3694. case UITouchPhaseBegan:
  3695. case UITouchPhaseMoved:
  3696. case UITouchPhaseStationary:
  3697. input.points[input.numPoints].x = location.x * gState.scaleFactor;
  3698. input.points[input.numPoints].y = location.y * gState.scaleFactor;
  3699. input.numPoints++;
  3700. break;
  3701. }
  3702. if (input.numPoints >= MAX_TOUCH_POINTS) {
  3703. break;
  3704. }
  3705. }
  3706. TigrMessageData message = {
  3707. .message = SET_INPUT,
  3708. .inputState = input,
  3709. };
  3710. writeToRenderThread(&message);
  3711. }
  3712. Class tigrAppDelegate() {
  3713. static Class delegateClass = 0;
  3714. if (delegateClass != 0) {
  3715. return delegateClass;
  3716. }
  3717. id application = objc_msgSend_id(class("UIApplication"), sel("sharedApplication"));
  3718. delegateClass = makeClass("TigrAppDelegate", "UIResponder");
  3719. addMethod(delegateClass, "application:didFinishLaunchingWithOptions:", didFinishLaunchingWithOptions, "c@:@@");
  3720. addMethod(delegateClass, "touchesBegan:withEvent:", touches, "v@:@@");
  3721. addMethod(delegateClass, "touchesMoved:withEvent:", touches, "v@:@@");
  3722. addMethod(delegateClass, "touchesEnded:withEvent:", touches, "v@:@@");
  3723. addMethod(delegateClass, "touchesCancelled:withEvent:", touches, "v@:@@");
  3724. addMethod(delegateClass, "glkView:drawInRect:", drawInRect, "v@:@{CGRect}");
  3725. addMethod(delegateClass, "renderMain", renderMain, "v@:");
  3726. objc_registerClassPair(delegateClass);
  3727. int fds[2];
  3728. if (pipe(fds) != 0) {
  3729. tigrError(0, "Failed to create message pipe");
  3730. }
  3731. int flags = fcntl(fds[0], F_GETFL, 0);
  3732. fcntl(fds[0], F_SETFL, flags | O_NONBLOCK);
  3733. gState.renderReadFd = fds[0];
  3734. gState.mainWriteFd = fds[1];
  3735. return delegateClass;
  3736. }
  3737. Tigr* tigrWindow(int w, int h, const char* title, int flags) {
  3738. int scale = 1;
  3739. if (flags & TIGR_AUTO) {
  3740. // Always use a 1:1 pixel size.
  3741. scale = 1;
  3742. } else {
  3743. // See how big we can make it and still fit on-screen.
  3744. scale = tigrCalcScale(w, h, gState.screenW, gState.screenH);
  3745. }
  3746. scale = tigrEnforceScale(scale, flags);
  3747. Tigr* bmp = tigrBitmap2(w, h, sizeof(TigrInternal));
  3748. bmp->handle = (void*)4711;
  3749. TigrInternal* win = tigrInternal(bmp);
  3750. win->shown = 0;
  3751. win->closed = 0;
  3752. win->scale = scale;
  3753. win->lastChar = 0;
  3754. win->flags = flags;
  3755. win->p1 = win->p2 = win->p3 = 0;
  3756. win->p4 = 1;
  3757. win->widgetsWanted = 0;
  3758. win->widgetAlpha = 0;
  3759. win->widgetsScale = 0;
  3760. win->widgets = 0;
  3761. win->gl.gl_legacy = 0;
  3762. tigrPosition(bmp, win->scale, bmp->w, bmp->h, win->pos);
  3763. tigrGAPICreate(bmp);
  3764. return bmp;
  3765. }
  3766. void processEvents(TigrInternal* win) {
  3767. memset(win->keys, 0, 255);
  3768. TigrMessageData data;
  3769. while (readFromMainThread(&data)) {
  3770. switch (data.message) {
  3771. case SET_INPUT:
  3772. gState.inputState = data.inputState;
  3773. break;
  3774. case KEY_EVENT:
  3775. win->keys[data.keyEvent.keyCode] = 1;
  3776. win->lastChar = data.keyEvent.codePoint;
  3777. break;
  3778. }
  3779. }
  3780. }
  3781. static int toWindowX(TigrInternal* win, int x) {
  3782. return (x - win->pos[0]) / win->scale;
  3783. }
  3784. static int toWindowY(TigrInternal* win, int y) {
  3785. return (y - win->pos[1]) / win->scale;
  3786. }
  3787. void tigrUpdate(Tigr* bmp) {
  3788. TigrInternal* win = tigrInternal(bmp);
  3789. processEvents(win);
  3790. win->numTouchPoints = gState.inputState.numPoints;
  3791. for (int i = 0; i < win->numTouchPoints; i++) {
  3792. win->touchPoints[i].x = toWindowX(win, gState.inputState.points[i].x);
  3793. win->touchPoints[i].y = toWindowY(win, gState.inputState.points[i].y);
  3794. }
  3795. win->mouseButtons = win->numTouchPoints;
  3796. if (win->mouseButtons > 0) {
  3797. win->mouseX = win->touchPoints[0].x;
  3798. win->mouseY = win->touchPoints[0].y;
  3799. }
  3800. if (win->flags & TIGR_AUTO) {
  3801. tigrResize(bmp, gState.screenW / win->scale, gState.screenH / win->scale);
  3802. } else {
  3803. win->scale = tigrEnforceScale(tigrCalcScale(bmp->w, bmp->h, gState.screenW, gState.screenH), win->flags);
  3804. }
  3805. tigrPosition(bmp, win->scale, gState.screenW, gState.screenH, win->pos);
  3806. tigrGAPIPresent(bmp, gState.screenW, gState.screenH);
  3807. waitForFrame();
  3808. }
  3809. int tigrClosed(Tigr* bmp) {
  3810. return 0;
  3811. }
  3812. void tigrError(Tigr* bmp, const char* message, ...) {
  3813. char tmp[1024];
  3814. va_list args;
  3815. va_start(args, message);
  3816. vsnprintf(tmp, sizeof(tmp), message, args);
  3817. tmp[sizeof(tmp) - 1] = 0;
  3818. va_end(args);
  3819. os_log_error(OS_LOG_DEFAULT, "tigr fatal error: %{public}s\n", tmp);
  3820. exit(1);
  3821. }
  3822. float tigrTime() {
  3823. return (float)gState.timeSinceLastDraw;
  3824. }
  3825. void tigrMouse(Tigr* bmp, int* x, int* y, int* buttons) {
  3826. TigrInternal* win = tigrInternal(bmp);
  3827. if (x) {
  3828. *x = win->mouseX;
  3829. }
  3830. if (y) {
  3831. *y = win->mouseY;
  3832. }
  3833. if (buttons) {
  3834. *buttons = win->mouseButtons;
  3835. }
  3836. }
  3837. int tigrTouch(Tigr* bmp, TigrTouchPoint* points, int maxPoints) {
  3838. TigrInternal* win = tigrInternal(bmp);
  3839. for (int i = 0; i < maxPoints && i < win->numTouchPoints; i++) {
  3840. points[i] = win->touchPoints[i];
  3841. }
  3842. return maxPoints < win->numTouchPoints ? maxPoints : win->numTouchPoints;
  3843. }
  3844. void tigrMouseWheel(Tigr* bmp, float* x, float* y) {
  3845. if (x) {
  3846. *x = 0;
  3847. }
  3848. if (y) {
  3849. *y = 0;
  3850. }
  3851. }
  3852. void tigrFree(Tigr* bmp) {
  3853. if (bmp->handle) {
  3854. TigrInternal* win = tigrInternal(bmp);
  3855. }
  3856. free(bmp->pix);
  3857. free(bmp);
  3858. }
  3859. int tigrGAPIBegin(Tigr* bmp) {
  3860. (void)bmp;
  3861. return 0;
  3862. }
  3863. int tigrGAPIEnd(Tigr* bmp) {
  3864. (void)bmp;
  3865. return 0;
  3866. }
  3867. int tigrKeyDown(Tigr* bmp, int key) {
  3868. TigrInternal* win;
  3869. assert(key < 256);
  3870. win = tigrInternal(bmp);
  3871. return win->keys[key];
  3872. }
  3873. int tigrKeyHeld(Tigr* bmp, int key) {
  3874. return tigrKeyDown(bmp, key);
  3875. }
  3876. int tigrReadChar(Tigr* bmp) {
  3877. TigrInternal* win = tigrInternal(bmp);
  3878. int c = win->lastChar;
  3879. win->lastChar = 0;
  3880. return c;
  3881. }
  3882. extern void* _tigrReadFile(const char* fileName, int* length);
  3883. void* tigrReadFile(const char* fileName, int* length) {
  3884. id mainBundle = objc_msgSend_id(class("NSBundle"), sel("mainBundle"));
  3885. id resourcePath = objc_msgSend_id(mainBundle, sel("resourcePath"));
  3886. resourcePath = joinNSStrings(resourcePath, makeNSString("/"));
  3887. resourcePath = joinNSStrings(resourcePath, makeNSString(fileName));
  3888. return _tigrReadFile(UTF8StringFromNSString(resourcePath), length);
  3889. }
  3890. #endif // __IOS__
  3891. #endif // #ifndef TIGR_HEADLESS
  3892. //////// End of inlined file: tigr_ios.c ////////
  3893. //////// Start of inlined file: tigr_android.h ////////
  3894. #ifndef TIGR_ANDROID_H
  3895. #define TIGR_ANDROID_H
  3896. #ifdef __ANDROID__
  3897. #include <android/input.h>
  3898. #include <android/native_window.h>
  3899. #include <EGL/egl.h>
  3900. typedef enum {
  3901. AE_INPUT,
  3902. AE_WINDOW_CREATED,
  3903. AE_WINDOW_DESTROYED,
  3904. AE_RESUME,
  3905. AE_CLOSE,
  3906. } AndroidEventType;
  3907. typedef struct {
  3908. AndroidEventType type;
  3909. AInputEvent* inputEvent;
  3910. ANativeWindow* window;
  3911. double time;
  3912. } AndroidEvent;
  3913. #ifdef __cplusplus
  3914. extern "C" {
  3915. #endif
  3916. /// Calls from TIGR to Android side, render thread
  3917. extern int android_pollEvent(int (*eventHandler)(AndroidEvent, void*), void*);
  3918. extern void android_swap(EGLDisplay display, EGLSurface surface);
  3919. extern void* android_loadAsset(const char* filename, int* outLength);
  3920. extern void android_showKeyboard(int show);
  3921. /// Calls from Android to TIGR side, main thread
  3922. void tigr_android_create();
  3923. void tigr_android_destroy();
  3924. #ifdef __cplusplus
  3925. }
  3926. #endif
  3927. #endif // __ANDROID__
  3928. #endif // TIGR_ANDROID_H
  3929. //////// End of inlined file: tigr_android.h ////////
  3930. //////// Start of inlined file: tigr_linux.c ////////
  3931. #ifndef TIGR_HEADLESS
  3932. //#include "tigr_internal.h"
  3933. #if __linux__ && !__ANDROID__
  3934. #include <stdio.h>
  3935. #include <stdlib.h>
  3936. #include <stdbool.h>
  3937. #include <string.h>
  3938. #include <stdarg.h>
  3939. #include <sys/time.h>
  3940. #include <X11/X.h>
  3941. #include <X11/Xlib.h>
  3942. #include <X11/Xlocale.h>
  3943. #include <X11/XKBlib.h>
  3944. #include <X11/Xatom.h>
  3945. #include <GL/glx.h>
  3946. static Display* dpy;
  3947. static Window root;
  3948. static XVisualInfo* vi;
  3949. static Atom wmDeleteMessage;
  3950. static XIM inputMethod;
  3951. static GLXFBConfig fbConfig;
  3952. static PFNGLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = 0;
  3953. static void tearDownX11Stuff() {
  3954. XCloseDisplay(dpy);
  3955. }
  3956. static void initX11Stuff() {
  3957. static int done = 0;
  3958. if (!done) {
  3959. dpy = XOpenDisplay(NULL);
  3960. if (dpy == NULL) {
  3961. tigrError(0, "Cannot connect to X server");
  3962. }
  3963. root = DefaultRootWindow(dpy);
  3964. static int attribList[] = { GLX_RENDER_TYPE,
  3965. GLX_RGBA_BIT,
  3966. GLX_DRAWABLE_TYPE,
  3967. GLX_WINDOW_BIT,
  3968. GLX_DOUBLEBUFFER,
  3969. 1,
  3970. GLX_RED_SIZE,
  3971. 1,
  3972. GLX_GREEN_SIZE,
  3973. 1,
  3974. GLX_BLUE_SIZE,
  3975. 1,
  3976. None };
  3977. int fbcCount = 0;
  3978. GLXFBConfig* fbc = glXChooseFBConfig(dpy, DefaultScreen(dpy), attribList, &fbcCount);
  3979. if (!fbc) {
  3980. tigrError(0, "Failed to choose FB config");
  3981. }
  3982. fbConfig = fbc[0];
  3983. XFree(fbc);
  3984. vi = glXGetVisualFromFBConfig(dpy, fbConfig);
  3985. if (vi == NULL) {
  3986. tigrError(0, "No appropriate visual found");
  3987. }
  3988. GLXContext tmpCtx = glXCreateContext(dpy, vi, 0, GL_TRUE);
  3989. glXCreateContextAttribsARB =
  3990. (PFNGLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB");
  3991. glXDestroyContext(dpy, tmpCtx);
  3992. if (!glXCreateContextAttribsARB) {
  3993. tigrError(0, "Failed to get glXCreateContextAttribsARB");
  3994. }
  3995. inputMethod = XOpenIM(dpy, NULL, NULL, NULL);
  3996. if (inputMethod == NULL) {
  3997. tigrError(0, "Failed to create input method");
  3998. }
  3999. wmDeleteMessage = XInternAtom(dpy, "WM_DELETE_WINDOW", False);
  4000. atexit(tearDownX11Stuff);
  4001. done = 1;
  4002. }
  4003. }
  4004. static int hasGLXExtension(Display* display, const char* wanted) {
  4005. const char* extensions = glXQueryExtensionsString(display, DefaultScreen(display));
  4006. char* dup = strdup(extensions);
  4007. char* found = 0;
  4008. for (char* start = dup;; start = 0) {
  4009. found = strtok(start, " ");
  4010. if (found == 0 || strcmp(found, wanted) == 0) {
  4011. break;
  4012. }
  4013. }
  4014. free(dup);
  4015. return found != 0;
  4016. }
  4017. static void setupVSync(Display* display, Window win) {
  4018. if (hasGLXExtension(display, "GLX_EXT_swap_control")) {
  4019. PFNGLXSWAPINTERVALEXTPROC glXSwapIntervalEXT =
  4020. (PFNGLXSWAPINTERVALEXTPROC)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalEXT");
  4021. if (glXSwapIntervalEXT) {
  4022. glXSwapIntervalEXT(display, win, 1);
  4023. }
  4024. } else if (hasGLXExtension(display, "GLX_MESA_swap_control")) {
  4025. PFNGLXSWAPINTERVALMESAPROC glXSwapIntervalMESA =
  4026. (PFNGLXSWAPINTERVALMESAPROC)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalMESA");
  4027. if (glXSwapIntervalMESA) {
  4028. glXSwapIntervalMESA(1);
  4029. }
  4030. } else if (hasGLXExtension(display, "GLX_SGI_swap_control")) {
  4031. PFNGLXSWAPINTERVALSGIPROC glXSwapIntervalSGI =
  4032. (PFNGLXSWAPINTERVALSGIPROC)glXGetProcAddressARB((const GLubyte*)"glXSwapIntervalSGI");
  4033. if (glXSwapIntervalSGI) {
  4034. glXSwapIntervalSGI(1);
  4035. }
  4036. }
  4037. }
  4038. static void tigrHideCursor(TigrInternal* win) {
  4039. Cursor invisibleCursor;
  4040. Pixmap bitmapNoData;
  4041. XColor black;
  4042. static char noData[] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  4043. black.red = black.green = black.blue = 0;
  4044. bitmapNoData = XCreateBitmapFromData(win->dpy, win->win, noData, 8, 8);
  4045. invisibleCursor = XCreatePixmapCursor(win->dpy, bitmapNoData, bitmapNoData, &black, &black, 0, 0);
  4046. XDefineCursor(win->dpy, win->win, invisibleCursor);
  4047. XFreeCursor(win->dpy, invisibleCursor);
  4048. XFreePixmap(win->dpy, bitmapNoData);
  4049. }
  4050. typedef struct {
  4051. unsigned long flags;
  4052. unsigned long functions;
  4053. unsigned long decorations;
  4054. long inputMode;
  4055. unsigned long status;
  4056. } WindowHints;
  4057. Tigr* tigrWindow(int w, int h, const char* title, int flags) {
  4058. Tigr* bmp = 0;
  4059. Colormap cmap;
  4060. XSetWindowAttributes swa;
  4061. Window xwin;
  4062. GLXContext glc;
  4063. XIC ic;
  4064. int scale;
  4065. initX11Stuff();
  4066. if (flags & TIGR_AUTO) {
  4067. // Always use a 1:1 pixel size, unless downscaled by tigrEnforceScale below.
  4068. scale = 1;
  4069. } else {
  4070. // See how big we can make it and still fit on-screen.
  4071. Screen* screen = DefaultScreenOfDisplay(dpy);
  4072. int maxW = WidthOfScreen(screen);
  4073. int maxH = HeightOfScreen(screen);
  4074. scale = tigrCalcScale(w, h, maxW, maxH);
  4075. }
  4076. scale = tigrEnforceScale(scale, flags);
  4077. cmap = XCreateColormap(dpy, root, vi->visual, AllocNone);
  4078. swa.colormap = cmap;
  4079. swa.event_mask = StructureNotifyMask;
  4080. // Create window of wanted size
  4081. xwin = XCreateWindow(dpy, root, 0, 0, w * scale, h * scale, 0, vi->depth, InputOutput, vi->visual,
  4082. CWColormap | CWEventMask, &swa);
  4083. XMapWindow(dpy, xwin);
  4084. if (flags & TIGR_FULLSCREEN) {
  4085. // https://superuser.com/questions/1680077/does-x11-actually-have-a-native-fullscreen-mode
  4086. Atom wm_state = XInternAtom(dpy, "_NET_WM_STATE", true);
  4087. Atom wm_fullscreen = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", true);
  4088. XChangeProperty(dpy, xwin, wm_state, XA_ATOM, 32, PropModeReplace, (unsigned char*)&wm_fullscreen, 1);
  4089. } else {
  4090. // Wait for window to get mapped
  4091. for (;;) {
  4092. XEvent e;
  4093. XNextEvent(dpy, &e);
  4094. if (e.type == MapNotify) {
  4095. break;
  4096. }
  4097. }
  4098. // Reset size if we did not get the window size we wanted above.
  4099. XWindowAttributes wa;
  4100. XGetWindowAttributes(dpy, xwin, &wa);
  4101. scale = tigrCalcScale(w, h, wa.width, wa.height);
  4102. scale = tigrEnforceScale(scale, flags);
  4103. XResizeWindow(dpy, xwin, w * scale, h * scale);
  4104. }
  4105. // Enable mouse events reporting (needed for mouse wheel events)
  4106. XSelectInput(dpy, xwin, ButtonPressMask);
  4107. XTextProperty prop;
  4108. int result = Xutf8TextListToTextProperty(dpy, (char**)&title, 1, XUTF8StringStyle, &prop);
  4109. if (result == Success) {
  4110. Atom wmName = XInternAtom(dpy, "_NET_WM_NAME", 0);
  4111. XSetTextProperty(dpy, xwin, &prop, wmName);
  4112. XFree(prop.value);
  4113. }
  4114. ic = XCreateIC(inputMethod, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, xwin, NULL);
  4115. if (ic == NULL) {
  4116. printf("Failed to create input context\n");
  4117. exit(0);
  4118. }
  4119. XSetICFocus(ic);
  4120. XSetWMProtocols(dpy, xwin, &wmDeleteMessage, 1);
  4121. int contextAttributes[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, 3, GLX_CONTEXT_MINOR_VERSION_ARB, 3, None };
  4122. glc = glXCreateContextAttribsARB(dpy, fbConfig, NULL, GL_TRUE, contextAttributes);
  4123. glXMakeCurrent(dpy, xwin, glc);
  4124. setupVSync(dpy, xwin);
  4125. bmp = tigrBitmap2(w, h, sizeof(TigrInternal));
  4126. bmp->handle = (void*)xwin;
  4127. TigrInternal* win = tigrInternal(bmp);
  4128. win->win = xwin;
  4129. win->dpy = dpy;
  4130. win->glc = glc;
  4131. win->ic = ic;
  4132. win->shown = 0;
  4133. win->closed = 0;
  4134. win->scale = scale;
  4135. win->lastChar = 0;
  4136. win->flags = flags;
  4137. win->p1 = win->p2 = win->p3 = 0;
  4138. win->p4 = 1;
  4139. win->widgetsWanted = 0;
  4140. win->widgetAlpha = 0;
  4141. win->widgetsScale = 0;
  4142. win->widgets = 0;
  4143. win->gl.gl_legacy = 0;
  4144. memset(win->keys, 0, 256);
  4145. memset(win->prev, 0, 256);
  4146. if (flags & TIGR_NOCURSOR) {
  4147. tigrHideCursor(win);
  4148. }
  4149. tigrPosition(bmp, win->scale, bmp->w, bmp->h, win->pos);
  4150. tigrGAPICreate(bmp);
  4151. tigrGAPIBegin(bmp);
  4152. return bmp;
  4153. }
  4154. int tigrClosed(Tigr* bmp) {
  4155. TigrInternal* win = tigrInternal(bmp);
  4156. return win->win == 0;
  4157. }
  4158. int tigrGAPIBegin(Tigr* bmp) {
  4159. TigrInternal* win = tigrInternal(bmp);
  4160. return glXMakeCurrent(win->dpy, win->win, win->glc) ? 0 : -1;
  4161. }
  4162. int tigrGAPIEnd(Tigr* bmp) {
  4163. (void)bmp;
  4164. return glXMakeCurrent(NULL, 0, 0) ? 0 : -1;
  4165. }
  4166. int tigrKeyDown(Tigr* bmp, int key) {
  4167. TigrInternal* win;
  4168. assert(key < 256);
  4169. win = tigrInternal(bmp);
  4170. return win->keys[key] && !win->prev[key];
  4171. }
  4172. int tigrKeyHeld(Tigr* bmp, int key) {
  4173. TigrInternal* win;
  4174. assert(key < 256);
  4175. win = tigrInternal(bmp);
  4176. return win->keys[key];
  4177. }
  4178. int tigrReadChar(Tigr* bmp) {
  4179. TigrInternal* win = tigrInternal(bmp);
  4180. int c = win->lastChar;
  4181. win->lastChar = 0;
  4182. return c;
  4183. }
  4184. uint8_t tigrKeyFromX11(KeySym sym) {
  4185. if (sym >= 'a' && sym <= 'z') {
  4186. return (uint8_t)sym - ('a' - 'A');
  4187. }
  4188. if (sym >= '0' && sym <= '9') {
  4189. return (uint8_t)sym;
  4190. }
  4191. switch (sym) {
  4192. case XK_KP_0:
  4193. return TK_PAD0;
  4194. case XK_KP_1:
  4195. return TK_PAD1;
  4196. case XK_KP_2:
  4197. return TK_PAD2;
  4198. case XK_KP_3:
  4199. return TK_PAD3;
  4200. case XK_KP_4:
  4201. return TK_PAD4;
  4202. case XK_KP_5:
  4203. return TK_PAD5;
  4204. case XK_KP_6:
  4205. return TK_PAD6;
  4206. case XK_KP_7:
  4207. return TK_PAD7;
  4208. case XK_KP_8:
  4209. return TK_PAD8;
  4210. case XK_KP_9:
  4211. return TK_PAD9;
  4212. case XK_KP_Multiply:
  4213. return TK_PADMUL;
  4214. case XK_KP_Divide:
  4215. return TK_PADDIV;
  4216. case XK_KP_Add:
  4217. return TK_PADADD;
  4218. case XK_KP_Subtract:
  4219. return TK_PADSUB;
  4220. case XK_KP_Decimal:
  4221. return TK_PADDOT;
  4222. case XK_KP_Enter:
  4223. return TK_PADENTER;
  4224. case XK_F1:
  4225. return TK_F1;
  4226. case XK_F2:
  4227. return TK_F2;
  4228. case XK_F3:
  4229. return TK_F3;
  4230. case XK_F4:
  4231. return TK_F4;
  4232. case XK_F5:
  4233. return TK_F5;
  4234. case XK_F6:
  4235. return TK_F6;
  4236. case XK_F7:
  4237. return TK_F7;
  4238. case XK_F8:
  4239. return TK_F8;
  4240. case XK_F9:
  4241. return TK_F9;
  4242. case XK_F10:
  4243. return TK_F10;
  4244. case XK_F11:
  4245. return TK_F11;
  4246. case XK_F12:
  4247. return TK_F12;
  4248. case XK_BackSpace:
  4249. return TK_BACKSPACE;
  4250. case XK_Tab:
  4251. return TK_TAB;
  4252. case XK_Return:
  4253. return TK_RETURN;
  4254. case XK_Pause:
  4255. return TK_PAUSE;
  4256. case XK_Caps_Lock:
  4257. return TK_CAPSLOCK;
  4258. case XK_Escape:
  4259. return TK_ESCAPE;
  4260. case XK_space:
  4261. return TK_SPACE;
  4262. case XK_Page_Up:
  4263. return TK_PAGEUP;
  4264. case XK_Page_Down:
  4265. return TK_PAGEDN;
  4266. case XK_End:
  4267. return TK_END;
  4268. case XK_Home:
  4269. return TK_HOME;
  4270. case XK_Left:
  4271. return TK_LEFT;
  4272. case XK_Up:
  4273. return TK_UP;
  4274. case XK_Right:
  4275. return TK_RIGHT;
  4276. case XK_Down:
  4277. return TK_DOWN;
  4278. case XK_Insert:
  4279. return TK_INSERT;
  4280. case XK_Delete:
  4281. return TK_DELETE;
  4282. case XK_Meta_L:
  4283. return TK_LWIN;
  4284. case XK_Meta_R:
  4285. return TK_RWIN;
  4286. case XK_Num_Lock:
  4287. return TK_NUMLOCK;
  4288. case XK_Scroll_Lock:
  4289. return TK_SCROLL;
  4290. case XK_Shift_L:
  4291. return TK_LSHIFT;
  4292. case XK_Shift_R:
  4293. return TK_RSHIFT;
  4294. case XK_Control_L:
  4295. return TK_LCONTROL;
  4296. case XK_Control_R:
  4297. return TK_RCONTROL;
  4298. case XK_Alt_L:
  4299. return TK_LALT;
  4300. case XK_Alt_R:
  4301. return TK_RALT;
  4302. case XK_semicolon:
  4303. return TK_SEMICOLON;
  4304. case XK_equal:
  4305. return TK_EQUALS;
  4306. case XK_comma:
  4307. return TK_COMMA;
  4308. case XK_minus:
  4309. return TK_MINUS;
  4310. case XK_period:
  4311. return TK_DOT;
  4312. case XK_slash:
  4313. return TK_SLASH;
  4314. case XK_grave:
  4315. return TK_BACKTICK;
  4316. case XK_bracketleft:
  4317. return TK_LSQUARE;
  4318. case XK_backslash:
  4319. return TK_BACKSLASH;
  4320. case XK_bracketright:
  4321. return TK_RSQUARE;
  4322. case XK_apostrophe:
  4323. return TK_TICK;
  4324. }
  4325. return 0;
  4326. }
  4327. static void tigrUpdateModifiers(TigrInternal* win) {
  4328. win->keys[TK_SHIFT] = win->keys[TK_LSHIFT] || win->keys[TK_RSHIFT];
  4329. win->keys[TK_CONTROL] = win->keys[TK_LCONTROL] || win->keys[TK_RCONTROL];
  4330. win->keys[TK_ALT] = win->keys[TK_LALT] || win->keys[TK_RALT];
  4331. }
  4332. static void tigrInterpretChar(TigrInternal* win, Window root, unsigned int keycode, unsigned int mask) {
  4333. XKeyEvent event;
  4334. memset(&event, 0, sizeof(event));
  4335. event.type = KeyPress;
  4336. event.display = win->dpy;
  4337. event.root = root;
  4338. event.window = win->win;
  4339. event.state = mask;
  4340. event.keycode = keycode;
  4341. char inputTextUTF8[10];
  4342. Status status = 0;
  4343. Xutf8LookupString(win->ic, &event, inputTextUTF8, sizeof(inputTextUTF8), NULL, &status);
  4344. if (status == XLookupChars) {
  4345. tigrDecodeUTF8(inputTextUTF8, &win->lastChar);
  4346. }
  4347. }
  4348. static void tigrProcessInput(TigrInternal* win, int winWidth, int winHeight) {
  4349. {
  4350. Window focused;
  4351. int revertTo;
  4352. XGetInputFocus(win->dpy, &focused, &revertTo);
  4353. if (win->win != focused) {
  4354. return;
  4355. }
  4356. }
  4357. Window root;
  4358. Window child;
  4359. int rootX;
  4360. int rootY;
  4361. int winX;
  4362. int winY;
  4363. unsigned int mask;
  4364. if (XQueryPointer(win->dpy, win->win, &root, &child, &rootX, &rootY, &winX, &winY, &mask)) {
  4365. static unsigned int prevButtons;
  4366. unsigned int buttons = mask & (Button1Mask | Button2Mask | Button3Mask);
  4367. win->mouseX = (winX - win->pos[0]) / win->scale;
  4368. win->mouseY = (winY - win->pos[1]) / win->scale;
  4369. if (buttons != prevButtons && (winX > 0 && winX < winWidth) && (winY > 0 && winY < winHeight)) {
  4370. win->mouseButtons = (buttons & Button1Mask) ? 1
  4371. : 0 | (buttons & Button3Mask) ? 2
  4372. : 0 | (buttons & Button2Mask) ? 4
  4373. : 0;
  4374. }
  4375. prevButtons = buttons;
  4376. }
  4377. // Retrieve mouse wheel events - Cannot be done in the XQueryPointer call
  4378. // -> https://comp.unix.programmer.narkive.com/eOnjkQ6L/xlib-xquerypointer-and-button4mask-button5mask#post2
  4379. // Button4 = WheelUp / Button5 = WheelDown
  4380. XEvent mouseButtonEvent;
  4381. while (XPending(win->dpy)) {
  4382. XPeekEvent(win->dpy, &mouseButtonEvent);
  4383. if (mouseButtonEvent.xany.type == ButtonPress) {
  4384. switch (mouseButtonEvent.xbutton.button) {
  4385. case Button4:
  4386. win->scrollDeltaY += 1;
  4387. break;
  4388. case Button5:
  4389. win->scrollDeltaY -= 1;
  4390. break;
  4391. case 6:
  4392. win->scrollDeltaX += 1;
  4393. break;
  4394. case 7:
  4395. win->scrollDeltaX -= 1;
  4396. break;
  4397. }
  4398. XNextEvent(win->dpy, &mouseButtonEvent);
  4399. } else {
  4400. break;
  4401. }
  4402. }
  4403. static char prevKeys[32];
  4404. char keys[32];
  4405. XQueryKeymap(win->dpy, keys);
  4406. for (int i = 0; i < 32; i++) {
  4407. char thisBlock = keys[i];
  4408. char prevBlock = prevKeys[i];
  4409. if (thisBlock != prevBlock) {
  4410. for (int j = 0; j < 8; j++) {
  4411. int thisBit = thisBlock & 1;
  4412. int prevBit = prevBlock & 1;
  4413. thisBlock >>= 1;
  4414. prevBlock >>= 1;
  4415. if (thisBit != prevBit) {
  4416. int keyCode = 8 * i + j;
  4417. KeySym keySym = XkbKeycodeToKeysym(win->dpy, keyCode, 0, 0);
  4418. if (keySym != NoSymbol) {
  4419. int key = tigrKeyFromX11(keySym);
  4420. win->keys[key] = thisBit;
  4421. tigrUpdateModifiers(win);
  4422. if (thisBit) {
  4423. tigrInterpretChar(win, root, keyCode, mask);
  4424. }
  4425. }
  4426. }
  4427. }
  4428. }
  4429. }
  4430. memcpy(prevKeys, keys, 32);
  4431. XEvent event;
  4432. while (XCheckTypedWindowEvent(win->dpy, win->win, ClientMessage, &event)) {
  4433. if (event.xclient.data.l[0] == wmDeleteMessage) {
  4434. glXMakeCurrent(win->dpy, None, NULL);
  4435. glXDestroyContext(win->dpy, win->glc);
  4436. XDestroyWindow(win->dpy, win->win);
  4437. win->win = 0;
  4438. }
  4439. }
  4440. XFlush(win->dpy);
  4441. }
  4442. void tigrUpdate(Tigr* bmp) {
  4443. XWindowAttributes gwa;
  4444. TigrInternal* win = tigrInternal(bmp);
  4445. memcpy(win->prev, win->keys, 256);
  4446. win->scrollDeltaX = 0;
  4447. win->scrollDeltaY = 0;
  4448. XGetWindowAttributes(win->dpy, win->win, &gwa);
  4449. if (win->flags & TIGR_AUTO)
  4450. tigrResize(bmp, gwa.width / win->scale, gwa.height / win->scale);
  4451. else
  4452. win->scale = tigrEnforceScale(tigrCalcScale(bmp->w, bmp->h, gwa.width, gwa.height), win->flags);
  4453. tigrPosition(bmp, win->scale, gwa.width, gwa.height, win->pos);
  4454. glXMakeCurrent(win->dpy, win->win, win->glc);
  4455. tigrGAPIPresent(bmp, gwa.width, gwa.height);
  4456. glXSwapBuffers(win->dpy, win->win);
  4457. tigrProcessInput(win, gwa.width, gwa.height);
  4458. }
  4459. void tigrFree(Tigr* bmp) {
  4460. if (bmp->handle) {
  4461. TigrInternal* win = tigrInternal(bmp);
  4462. if (win->win) {
  4463. glXMakeCurrent(win->dpy, None, NULL);
  4464. glXDestroyContext(win->dpy, win->glc);
  4465. XDestroyWindow(win->dpy, win->win);
  4466. win->win = 0;
  4467. }
  4468. }
  4469. free(bmp->pix);
  4470. free(bmp);
  4471. }
  4472. void tigrError(Tigr* bmp, const char* message, ...) {
  4473. char tmp[1024];
  4474. va_list args;
  4475. va_start(args, message);
  4476. vsnprintf(tmp, sizeof(tmp), message, args);
  4477. tmp[sizeof(tmp) - 1] = 0;
  4478. va_end(args);
  4479. printf("tigr fatal error: %s\n", tmp);
  4480. exit(1);
  4481. }
  4482. float tigrTime() {
  4483. static double lastTime = 0;
  4484. struct timeval tv;
  4485. gettimeofday(&tv, NULL);
  4486. double now = (double)tv.tv_sec + (tv.tv_usec / 1000000.0);
  4487. double elapsed = lastTime == 0 ? 0 : now - lastTime;
  4488. lastTime = now;
  4489. return (float)elapsed;
  4490. }
  4491. void tigrMouse(Tigr* bmp, int* x, int* y, int* buttons) {
  4492. TigrInternal* win = tigrInternal(bmp);
  4493. if (x) {
  4494. *x = win->mouseX;
  4495. }
  4496. if (y) {
  4497. *y = win->mouseY;
  4498. }
  4499. if (buttons) {
  4500. *buttons = win->mouseButtons;
  4501. }
  4502. }
  4503. int tigrTouch(Tigr* bmp, TigrTouchPoint* points, int maxPoints) {
  4504. int buttons = 0;
  4505. if (maxPoints > 0) {
  4506. tigrMouse(bmp, &points->x, &points->y, &buttons);
  4507. }
  4508. return buttons ? 1 : 0;
  4509. }
  4510. void tigrScrollWheel(Tigr* bmp, float* x, float* y) {
  4511. TigrInternal* win;
  4512. win = tigrInternal(bmp);
  4513. if (x) {
  4514. *x = win->scrollDeltaX;
  4515. }
  4516. if (y) {
  4517. *y = win->scrollDeltaY;
  4518. }
  4519. }
  4520. #endif // __linux__ && !__ANDROID__
  4521. #endif // #ifndef TIGR_HEADLESS
  4522. //////// End of inlined file: tigr_linux.c ////////
  4523. //////// Start of inlined file: tigr_android.c ////////
  4524. #ifndef TIGR_HEADLESS
  4525. //#include "tigr_internal.h"
  4526. #ifdef __ANDROID__
  4527. #include <stdio.h>
  4528. #include <stdlib.h>
  4529. #include <string.h>
  4530. #include <time.h>
  4531. #include <android/log.h>
  4532. #include <android/native_window.h>
  4533. #include <android/input.h>
  4534. #ifndef NDEBUG
  4535. #define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, "tigr", __VA_ARGS__))
  4536. #else
  4537. #define LOGD(...) ((void)0)
  4538. #endif
  4539. #define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "tigr", __VA_ARGS__))
  4540. #define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "tigr", __VA_ARGS__))
  4541. typedef struct {
  4542. TigrTouchPoint points[MAX_TOUCH_POINTS];
  4543. int numPoints;
  4544. } InputState;
  4545. /// Global state
  4546. static struct {
  4547. ANativeWindow* window;
  4548. InputState inputState;
  4549. EGLDisplay display;
  4550. EGLSurface surface;
  4551. EGLint screenW;
  4552. EGLint screenH;
  4553. EGLConfig config;
  4554. double lastTime;
  4555. int closed;
  4556. } gState = {
  4557. .window = 0,
  4558. .inputState = {
  4559. .numPoints = 0,
  4560. },
  4561. .display = EGL_NO_DISPLAY,
  4562. .surface = EGL_NO_SURFACE,
  4563. .screenW = 0,
  4564. .screenH = 0,
  4565. .config = 0,
  4566. .lastTime = 0,
  4567. .closed = 0,
  4568. };
  4569. static const EGLint contextAttribs[] = { EGL_CONTEXT_MAJOR_VERSION, 3, EGL_CONTEXT_MINOR_VERSION, 0, EGL_NONE };
  4570. static EGLConfig getGLConfig(EGLDisplay display) {
  4571. EGLConfig config = 0;
  4572. const EGLint attribs[] = { EGL_SURFACE_TYPE, EGL_WINDOW_BIT, EGL_BLUE_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_RED_SIZE, 8,
  4573. EGL_NONE };
  4574. EGLint numConfigs;
  4575. eglChooseConfig(display, attribs, NULL, 0, &numConfigs);
  4576. EGLConfig* supportedConfigs = (EGLConfig*)malloc(sizeof(EGLConfig) * numConfigs);
  4577. eglChooseConfig(display, attribs, supportedConfigs, numConfigs, &numConfigs);
  4578. int i = 0;
  4579. for (; i < numConfigs; i++) {
  4580. EGLConfig* cfg = supportedConfigs[i];
  4581. EGLint r, g, b, d;
  4582. if (eglGetConfigAttrib(display, cfg, EGL_RED_SIZE, &r) &&
  4583. eglGetConfigAttrib(display, cfg, EGL_GREEN_SIZE, &g) &&
  4584. eglGetConfigAttrib(display, cfg, EGL_BLUE_SIZE, &b) &&
  4585. eglGetConfigAttrib(display, cfg, EGL_DEPTH_SIZE, &d) && r == 8 && g == 8 && b == 8 && d == 0) {
  4586. config = supportedConfigs[i];
  4587. break;
  4588. }
  4589. }
  4590. if (i == numConfigs) {
  4591. config = supportedConfigs[0];
  4592. }
  4593. if (config == NULL) {
  4594. tigrError(NULL, "Unable to initialize EGLConfig");
  4595. }
  4596. free(supportedConfigs);
  4597. return config;
  4598. }
  4599. /// Android interface, called from main thread
  4600. void tigr_android_create() {
  4601. gState.closed = 0;
  4602. gState.window = 0;
  4603. gState.inputState.numPoints = 0;
  4604. gState.surface = EGL_NO_SURFACE;
  4605. gState.lastTime = 0;
  4606. if (gState.display == EGL_NO_DISPLAY) {
  4607. gState.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  4608. EGLBoolean status = eglInitialize(gState.display, NULL, NULL);
  4609. if (!status) {
  4610. tigrError(NULL, "Failed to init EGL");
  4611. }
  4612. gState.config = getGLConfig(gState.display);
  4613. }
  4614. }
  4615. void tigr_android_destroy() {
  4616. eglTerminate(gState.display);
  4617. gState.display = EGL_NO_DISPLAY;
  4618. }
  4619. /// Internals ///
  4620. static void logEglError() {
  4621. int error = eglGetError();
  4622. switch (error) {
  4623. case EGL_BAD_DISPLAY:
  4624. LOGE("EGL error: Bad display");
  4625. break;
  4626. case EGL_NOT_INITIALIZED:
  4627. LOGE("EGL error: Not initialized");
  4628. break;
  4629. case EGL_BAD_NATIVE_WINDOW:
  4630. LOGE("EGL error: Bad native window");
  4631. break;
  4632. case EGL_BAD_ALLOC:
  4633. LOGE("EGL error: Bad alloc");
  4634. break;
  4635. case EGL_BAD_MATCH:
  4636. LOGE("EGL error: Bad match");
  4637. break;
  4638. default:
  4639. LOGE("EGL error: %d", error);
  4640. }
  4641. }
  4642. static void setupOpenGL() {
  4643. LOGD("setupOpenGL");
  4644. assert(gState.surface == EGL_NO_SURFACE);
  4645. assert(gState.window != 0);
  4646. gState.surface = eglCreateWindowSurface(gState.display, gState.config, gState.window, NULL);
  4647. if (gState.surface == EGL_NO_SURFACE) {
  4648. logEglError();
  4649. }
  4650. assert(gState.surface != EGL_NO_SURFACE);
  4651. eglQuerySurface(gState.display, gState.surface, EGL_WIDTH, &gState.screenW);
  4652. eglQuerySurface(gState.display, gState.surface, EGL_HEIGHT, &gState.screenH);
  4653. LOGD("Screen is %d x %d", gState.screenW, gState.screenH);
  4654. }
  4655. static void tearDownOpenGL() {
  4656. LOGD("tearDownOpenGL");
  4657. if (gState.display != EGL_NO_DISPLAY) {
  4658. eglMakeCurrent(gState.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  4659. if (gState.surface != EGL_NO_SURFACE) {
  4660. LOGD("eglDestroySurface");
  4661. if (!eglDestroySurface(gState.display, gState.surface)) {
  4662. logEglError();
  4663. }
  4664. gState.surface = EGL_NO_SURFACE;
  4665. }
  4666. }
  4667. }
  4668. static int tigrKeyFromAndroidKey(int key) {
  4669. switch (key) {
  4670. case AKEYCODE_Q:
  4671. return 'Q';
  4672. case AKEYCODE_W:
  4673. return 'W';
  4674. case AKEYCODE_E:
  4675. return 'E';
  4676. case AKEYCODE_R:
  4677. return 'R';
  4678. case AKEYCODE_T:
  4679. return 'T';
  4680. case AKEYCODE_Y:
  4681. return 'Y';
  4682. case AKEYCODE_U:
  4683. return 'U';
  4684. case AKEYCODE_I:
  4685. return 'I';
  4686. case AKEYCODE_O:
  4687. return 'O';
  4688. case AKEYCODE_P:
  4689. return 'P';
  4690. case AKEYCODE_A:
  4691. return 'A';
  4692. case AKEYCODE_S:
  4693. return 'S';
  4694. case AKEYCODE_D:
  4695. return 'D';
  4696. case AKEYCODE_F:
  4697. return 'F';
  4698. case AKEYCODE_G:
  4699. return 'G';
  4700. case AKEYCODE_H:
  4701. return 'H';
  4702. case AKEYCODE_J:
  4703. return 'J';
  4704. case AKEYCODE_K:
  4705. return 'K';
  4706. case AKEYCODE_L:
  4707. return 'L';
  4708. case AKEYCODE_Z:
  4709. return 'Z';
  4710. case AKEYCODE_X:
  4711. return 'X';
  4712. case AKEYCODE_C:
  4713. return 'C';
  4714. case AKEYCODE_V:
  4715. return 'V';
  4716. case AKEYCODE_B:
  4717. return 'B';
  4718. case AKEYCODE_N:
  4719. return 'N';
  4720. case AKEYCODE_M:
  4721. return 'M';
  4722. case AKEYCODE_0:
  4723. return '0';
  4724. case AKEYCODE_1:
  4725. return '1';
  4726. case AKEYCODE_2:
  4727. return '2';
  4728. case AKEYCODE_3:
  4729. return '3';
  4730. case AKEYCODE_4:
  4731. return '4';
  4732. case AKEYCODE_5:
  4733. return '5';
  4734. case AKEYCODE_6:
  4735. return '6';
  4736. case AKEYCODE_7:
  4737. return '7';
  4738. case AKEYCODE_8:
  4739. return '8';
  4740. case AKEYCODE_9:
  4741. return '9';
  4742. case AKEYCODE_NUMPAD_0:
  4743. return TK_PAD0;
  4744. case AKEYCODE_NUMPAD_1:
  4745. return TK_PAD1;
  4746. case AKEYCODE_NUMPAD_2:
  4747. return TK_PAD2;
  4748. case AKEYCODE_NUMPAD_3:
  4749. return TK_PAD3;
  4750. case AKEYCODE_NUMPAD_4:
  4751. return TK_PAD4;
  4752. case AKEYCODE_NUMPAD_5:
  4753. return TK_PAD5;
  4754. case AKEYCODE_NUMPAD_6:
  4755. return TK_PAD6;
  4756. case AKEYCODE_NUMPAD_7:
  4757. return TK_PAD7;
  4758. case AKEYCODE_NUMPAD_8:
  4759. return TK_PAD8;
  4760. case AKEYCODE_NUMPAD_9:
  4761. return TK_PAD9;
  4762. case AKEYCODE_NUMPAD_MULTIPLY:
  4763. return TK_PADMUL;
  4764. case AKEYCODE_NUMPAD_DIVIDE:
  4765. return TK_PADDIV;
  4766. case AKEYCODE_NUMPAD_ADD:
  4767. return TK_PADADD;
  4768. case AKEYCODE_NUMPAD_SUBTRACT:
  4769. return TK_PADSUB;
  4770. case AKEYCODE_NUMPAD_ENTER:
  4771. return TK_PADENTER;
  4772. case AKEYCODE_NUMPAD_DOT:
  4773. return TK_PADDOT;
  4774. case AKEYCODE_F1:
  4775. return TK_F1;
  4776. case AKEYCODE_F2:
  4777. return TK_F2;
  4778. case AKEYCODE_F3:
  4779. return TK_F3;
  4780. case AKEYCODE_F4:
  4781. return TK_F4;
  4782. case AKEYCODE_F5:
  4783. return TK_F5;
  4784. case AKEYCODE_F6:
  4785. return TK_F6;
  4786. case AKEYCODE_F7:
  4787. return TK_F7;
  4788. case AKEYCODE_F8:
  4789. return TK_F8;
  4790. case AKEYCODE_F9:
  4791. return TK_F9;
  4792. case AKEYCODE_F10:
  4793. return TK_F10;
  4794. case AKEYCODE_F11:
  4795. return TK_F11;
  4796. case AKEYCODE_F12:
  4797. return TK_F12;
  4798. case AKEYCODE_SHIFT_LEFT:
  4799. return TK_LSHIFT;
  4800. case AKEYCODE_SHIFT_RIGHT:
  4801. return TK_RSHIFT;
  4802. case AKEYCODE_CTRL_LEFT:
  4803. return TK_LCONTROL;
  4804. case AKEYCODE_CTRL_RIGHT:
  4805. return TK_RCONTROL;
  4806. case AKEYCODE_ALT_LEFT:
  4807. return TK_LALT;
  4808. case AKEYCODE_ALT_RIGHT:
  4809. return TK_RALT;
  4810. case AKEYCODE_META_LEFT:
  4811. return TK_LWIN;
  4812. case AKEYCODE_META_RIGHT:
  4813. return TK_RWIN;
  4814. case AKEYCODE_DEL:
  4815. return TK_BACKSPACE;
  4816. case AKEYCODE_TAB:
  4817. return TK_TAB;
  4818. case AKEYCODE_ENTER:
  4819. return TK_RETURN;
  4820. case AKEYCODE_CAPS_LOCK:
  4821. return TK_CAPSLOCK;
  4822. case AKEYCODE_ESCAPE:
  4823. case AKEYCODE_BACK:
  4824. return TK_ESCAPE;
  4825. case AKEYCODE_SPACE:
  4826. return TK_SPACE;
  4827. case AKEYCODE_PAGE_UP:
  4828. return TK_PAGEUP;
  4829. case AKEYCODE_PAGE_DOWN:
  4830. return TK_PAGEDN;
  4831. case AKEYCODE_MOVE_END:
  4832. return TK_END;
  4833. case AKEYCODE_MOVE_HOME:
  4834. return TK_HOME;
  4835. case AKEYCODE_DPAD_LEFT:
  4836. return TK_LEFT;
  4837. case AKEYCODE_DPAD_RIGHT:
  4838. return TK_RIGHT;
  4839. case AKEYCODE_DPAD_UP:
  4840. return TK_UP;
  4841. case AKEYCODE_DPAD_DOWN:
  4842. return TK_DOWN;
  4843. case AKEYCODE_INSERT:
  4844. return TK_INSERT;
  4845. case AKEYCODE_FORWARD_DEL:
  4846. return TK_DELETE;
  4847. case AKEYCODE_NUM_LOCK:
  4848. return TK_NUMLOCK;
  4849. case AKEYCODE_SCROLL_LOCK:
  4850. return TK_SCROLL;
  4851. case AKEYCODE_SEMICOLON:
  4852. return TK_SEMICOLON;
  4853. case AKEYCODE_EQUALS:
  4854. return TK_EQUALS;
  4855. case AKEYCODE_COMMA:
  4856. return TK_COMMA;
  4857. case AKEYCODE_MINUS:
  4858. return TK_MINUS;
  4859. case AKEYCODE_PERIOD:
  4860. return TK_DOT;
  4861. case AKEYCODE_SLASH:
  4862. return TK_SLASH;
  4863. case AKEYCODE_BACKSLASH:
  4864. return TK_BACKSLASH;
  4865. case AKEYCODE_GRAVE:
  4866. return TK_BACKTICK;
  4867. case AKEYCODE_APOSTROPHE:
  4868. return TK_TICK;
  4869. case AKEYCODE_LEFT_BRACKET:
  4870. return TK_LSQUARE;
  4871. case AKEYCODE_RIGHT_BRACKET:
  4872. return TK_RSQUARE;
  4873. default:
  4874. return 0;
  4875. }
  4876. }
  4877. static int processInputEvent(AInputEvent* event, TigrInternal* win) {
  4878. if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_MOTION) {
  4879. int32_t action = AMotionEvent_getAction(event);
  4880. int32_t actionCode = action & AMOTION_EVENT_ACTION_MASK;
  4881. size_t touchPoints = AMotionEvent_getPointerCount(event);
  4882. size_t releasedIndex = -1;
  4883. if (actionCode == AMOTION_EVENT_ACTION_POINTER_UP) {
  4884. releasedIndex =
  4885. (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
  4886. }
  4887. size_t targetPointCount = 0;
  4888. for (size_t i = 0; i < touchPoints && i < MAX_TOUCH_POINTS; i++) {
  4889. if (i == releasedIndex) {
  4890. continue;
  4891. }
  4892. gState.inputState.points[targetPointCount].x = AMotionEvent_getX(event, i);
  4893. gState.inputState.points[targetPointCount].y = AMotionEvent_getY(event, i);
  4894. targetPointCount++;
  4895. }
  4896. if (actionCode == AMOTION_EVENT_ACTION_UP || actionCode == AMOTION_EVENT_ACTION_CANCEL) {
  4897. gState.inputState.numPoints = 0;
  4898. } else {
  4899. gState.inputState.numPoints = targetPointCount;
  4900. }
  4901. return 1;
  4902. } else if (AInputEvent_getType(event) == AINPUT_EVENT_TYPE_KEY) {
  4903. if (!win) {
  4904. return 1;
  4905. }
  4906. int32_t deviceID = AInputEvent_getDeviceId(event);
  4907. // KeyCharacterMap#VIRTUAL_KEYBOARD == -1
  4908. if (deviceID != -1) {
  4909. return 1;
  4910. }
  4911. int32_t action = AKeyEvent_getAction(event);
  4912. int32_t keyCode = AKeyEvent_getKeyCode(event);
  4913. int key = tigrKeyFromAndroidKey(keyCode);
  4914. // We pass the character in the scancode field from the Java side
  4915. int32_t unicodeChar = AKeyEvent_getScanCode(event);
  4916. if (action == AKEY_EVENT_ACTION_DOWN) {
  4917. win->keys[key] = 1;
  4918. win->lastChar = unicodeChar;
  4919. } else if (action == AKEY_EVENT_ACTION_UP) {
  4920. win->released[key] = 1;
  4921. }
  4922. return 1;
  4923. }
  4924. return 0;
  4925. }
  4926. static int handleEvent(AndroidEvent event, void* userData) {
  4927. switch (event.type) {
  4928. case AE_WINDOW_CREATED:
  4929. gState.window = event.window;
  4930. setupOpenGL();
  4931. break;
  4932. case AE_WINDOW_DESTROYED:
  4933. tearDownOpenGL();
  4934. gState.window = 0;
  4935. break;
  4936. case AE_INPUT:
  4937. return processInputEvent(event.inputEvent, (TigrInternal*)userData);
  4938. case AE_RESUME:
  4939. gState.lastTime = event.time;
  4940. break;
  4941. case AE_CLOSE:
  4942. gState.closed = 1;
  4943. break;
  4944. default:
  4945. LOGE("Unhandled event type: %d", event.type);
  4946. return 0;
  4947. }
  4948. return 1;
  4949. }
  4950. static int processEvents(TigrInternal* win) {
  4951. if (gState.closed) {
  4952. return 0;
  4953. }
  4954. while (android_pollEvent(handleEvent, win)) {
  4955. if (gState.closed) {
  4956. return 0;
  4957. }
  4958. }
  4959. return 1;
  4960. }
  4961. static Tigr* refreshWindow(Tigr* bmp) {
  4962. if (bmp->handle == gState.window) {
  4963. return bmp;
  4964. }
  4965. bmp->handle = gState.window;
  4966. if (gState.window == 0) {
  4967. return 0;
  4968. }
  4969. TigrInternal* win = tigrInternal(bmp);
  4970. int scale = 1;
  4971. if (win->flags & TIGR_AUTO) {
  4972. // Always use a 1:1 pixel size.
  4973. scale = 1;
  4974. } else {
  4975. // See how big we can make it and still fit on-screen.
  4976. scale = tigrCalcScale(bmp->w, bmp->h, gState.screenW, gState.screenH);
  4977. }
  4978. win->scale = tigrEnforceScale(scale, win->flags);
  4979. return bmp;
  4980. }
  4981. /// TIGR interface implementation, called from render thread ///
  4982. Tigr* tigrWindow(int w, int h, const char* title, int flags) {
  4983. while (gState.window == NULL) {
  4984. if (!processEvents(0)) {
  4985. return NULL;
  4986. }
  4987. }
  4988. EGLContext context = eglCreateContext(gState.display, gState.config, NULL, contextAttribs);
  4989. int scale = 1;
  4990. if (flags & TIGR_AUTO) {
  4991. // Always use a 1:1 pixel size.
  4992. scale = 1;
  4993. } else {
  4994. // See how big we can make it and still fit on-screen.
  4995. scale = tigrCalcScale(w, h, gState.screenW, gState.screenH);
  4996. }
  4997. scale = tigrEnforceScale(scale, flags);
  4998. Tigr* bmp = tigrBitmap2(w, h, sizeof(TigrInternal));
  4999. bmp->handle = (void*)gState.window;
  5000. TigrInternal* win = tigrInternal(bmp);
  5001. win->context = context;
  5002. win->shown = 0;
  5003. win->closed = 0;
  5004. win->scale = scale;
  5005. win->lastChar = 0;
  5006. win->flags = flags;
  5007. win->p1 = win->p2 = win->p3 = 0;
  5008. win->p4 = 1;
  5009. win->widgetsWanted = 0;
  5010. win->widgetAlpha = 0;
  5011. win->widgetsScale = 0;
  5012. win->widgets = 0;
  5013. win->gl.gl_legacy = 0;
  5014. memset(win->keys, 0, 256);
  5015. memset(win->prev, 0, 256);
  5016. memset(win->released, 0, 256);
  5017. tigrPosition(bmp, win->scale, bmp->w, bmp->h, win->pos);
  5018. if (eglMakeCurrent(gState.display, gState.surface, gState.surface, context) == EGL_FALSE) {
  5019. LOGE("Unable to eglMakeCurrent");
  5020. return 0;
  5021. }
  5022. tigrGAPICreate(bmp);
  5023. return bmp;
  5024. }
  5025. int tigrClosed(Tigr* bmp) {
  5026. TigrInternal* win = tigrInternal(bmp);
  5027. return win->closed;
  5028. }
  5029. int tigrGAPIBegin(Tigr* bmp) {
  5030. assert(gState.display != EGL_NO_DISPLAY);
  5031. assert(gState.surface != EGL_NO_SURFACE);
  5032. TigrInternal* win = tigrInternal(bmp);
  5033. if (eglMakeCurrent(gState.display, gState.surface, gState.surface, win->context) == EGL_FALSE) {
  5034. return -1;
  5035. }
  5036. return 0;
  5037. }
  5038. int tigrGAPIEnd(Tigr* bmp) {
  5039. (void)bmp;
  5040. eglMakeCurrent(gState.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  5041. return 0;
  5042. }
  5043. int tigrKeyDown(Tigr* bmp, int key) {
  5044. TigrInternal* win;
  5045. assert(key < 256);
  5046. win = tigrInternal(bmp);
  5047. return win->keys[key] && !win->prev[key];
  5048. }
  5049. int tigrKeyHeld(Tigr* bmp, int key) {
  5050. TigrInternal* win;
  5051. assert(key < 256);
  5052. win = tigrInternal(bmp);
  5053. return win->keys[key];
  5054. }
  5055. int tigrReadChar(Tigr* bmp) {
  5056. TigrInternal* win = tigrInternal(bmp);
  5057. int c = win->lastChar;
  5058. win->lastChar = 0;
  5059. return c;
  5060. }
  5061. static void tigrUpdateModifiers(TigrInternal* win) {
  5062. win->keys[TK_SHIFT] = win->keys[TK_LSHIFT] || win->keys[TK_RSHIFT];
  5063. win->keys[TK_CONTROL] = win->keys[TK_LCONTROL] || win->keys[TK_RCONTROL];
  5064. win->keys[TK_ALT] = win->keys[TK_LALT] || win->keys[TK_RALT];
  5065. }
  5066. static int toWindowX(TigrInternal* win, int x) {
  5067. return (x - win->pos[0]) / win->scale;
  5068. }
  5069. static int toWindowY(TigrInternal* win, int y) {
  5070. return (y - win->pos[1]) / win->scale;
  5071. }
  5072. void tigrUpdate(Tigr* bmp) {
  5073. TigrInternal* win = tigrInternal(bmp);
  5074. memcpy(win->prev, win->keys, 256);
  5075. for (int i = 0; i < 256; i++) {
  5076. win->keys[i] ^= win->released[i];
  5077. win->released[i] = 0;
  5078. }
  5079. if (!processEvents(win)) {
  5080. win->closed = 1;
  5081. return;
  5082. }
  5083. tigrUpdateModifiers(win);
  5084. if (gState.window == 0) {
  5085. return;
  5086. }
  5087. bmp = refreshWindow(bmp);
  5088. if (bmp == 0) {
  5089. return;
  5090. }
  5091. win->numTouchPoints = gState.inputState.numPoints;
  5092. for (int i = 0; i < win->numTouchPoints; i++) {
  5093. win->touchPoints[i].x = toWindowX(win, gState.inputState.points[i].x);
  5094. win->touchPoints[i].y = toWindowY(win, gState.inputState.points[i].y);
  5095. }
  5096. win->mouseButtons = win->numTouchPoints;
  5097. if (win->mouseButtons > 0) {
  5098. win->mouseX = win->touchPoints[0].x;
  5099. win->mouseY = win->touchPoints[0].y;
  5100. }
  5101. if (win->flags & TIGR_AUTO) {
  5102. tigrResize(bmp, gState.screenW / win->scale, gState.screenH / win->scale);
  5103. } else {
  5104. win->scale = tigrEnforceScale(tigrCalcScale(bmp->w, bmp->h, gState.screenW, gState.screenH), win->flags);
  5105. }
  5106. tigrPosition(bmp, win->scale, gState.screenW, gState.screenH, win->pos);
  5107. tigrGAPIBegin(bmp);
  5108. tigrGAPIPresent(bmp, gState.screenW, gState.screenH);
  5109. android_swap(gState.display, gState.surface);
  5110. tigrGAPIEnd(bmp);
  5111. }
  5112. void tigrFree(Tigr* bmp) {
  5113. if (bmp->handle) {
  5114. TigrInternal* win = tigrInternal(bmp);
  5115. eglMakeCurrent(gState.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  5116. if (win->context != EGL_NO_CONTEXT) {
  5117. // Win closed means app windows has closed, and the call would fail.
  5118. if (!win->closed) {
  5119. tigrGAPIDestroy(bmp);
  5120. }
  5121. eglDestroyContext(gState.display, win->context);
  5122. }
  5123. win->context = EGL_NO_CONTEXT;
  5124. }
  5125. free(bmp->pix);
  5126. free(bmp);
  5127. }
  5128. void tigrError(Tigr* bmp, const char* message, ...) {
  5129. char tmp[1024];
  5130. va_list args;
  5131. va_start(args, message);
  5132. vsnprintf(tmp, sizeof(tmp), message, args);
  5133. tmp[sizeof(tmp) - 1] = 0;
  5134. va_end(args);
  5135. LOGE("tigr fatal error: %s\n", tmp);
  5136. exit(1);
  5137. }
  5138. float tigrTime() {
  5139. struct timespec ts;
  5140. clock_gettime(CLOCK_MONOTONIC, &ts);
  5141. double now = (double)ts.tv_sec + (ts.tv_nsec / 1000000000.0);
  5142. double elapsed = gState.lastTime == 0 ? 0 : now - gState.lastTime;
  5143. gState.lastTime = now;
  5144. return (float)elapsed;
  5145. }
  5146. void tigrMouse(Tigr* bmp, int* x, int* y, int* buttons) {
  5147. TigrInternal* win = tigrInternal(bmp);
  5148. if (x) {
  5149. *x = win->mouseX;
  5150. }
  5151. if (y) {
  5152. *y = win->mouseY;
  5153. }
  5154. if (buttons) {
  5155. *buttons = win->mouseButtons;
  5156. }
  5157. }
  5158. int tigrTouch(Tigr* bmp, TigrTouchPoint* points, int maxPoints) {
  5159. TigrInternal* win = tigrInternal(bmp);
  5160. for (int i = 0; i < maxPoints && i < win->numTouchPoints; i++) {
  5161. points[i] = win->touchPoints[i];
  5162. }
  5163. return maxPoints < win->numTouchPoints ? maxPoints : win->numTouchPoints;
  5164. }
  5165. void tigrMouseWheel(Tigr* bmp, float* x, float* y) {
  5166. if (x) {
  5167. *x = 0;
  5168. }
  5169. if (y) {
  5170. *y = 0;
  5171. }
  5172. }
  5173. void* tigrReadFile(const char* fileName, int* length) {
  5174. if (length != 0) {
  5175. *length = 0;
  5176. }
  5177. void* asset = android_loadAsset(fileName, length);
  5178. return asset;
  5179. }
  5180. #endif // __ANDROID__
  5181. #endif // #ifndef TIGR_HEADLESS
  5182. //////// End of inlined file: tigr_android.c ////////
  5183. //////// Start of inlined file: tigr_gl.c ////////
  5184. #ifndef TIGR_HEADLESS
  5185. //#include "tigr_internal.h"
  5186. #include <assert.h>
  5187. #ifdef TIGR_GAPI_GL
  5188. #if __linux__
  5189. #if __ANDROID__
  5190. #include <GLES3/gl3.h>
  5191. #else
  5192. #define GLX_GLXEXT_PROTOTYPES
  5193. #include <GL/glext.h>
  5194. #endif
  5195. #endif
  5196. extern const char tigr_upscale_gl_vs[], tigr_upscale_gl_fs[], tigr_default_fx_gl_fs[];
  5197. extern const int tigr_upscale_gl_vs_size, tigr_upscale_gl_fs_size, tigr_default_fx_gl_fs_size;
  5198. #ifdef _WIN32
  5199. #ifdef TIGR_GAPI_GL_WIN_USE_GLEXT
  5200. #include <glext.h>
  5201. #include <wglext.h>
  5202. #else // short version of glext.h and wglext.h so we don't need to depend on them
  5203. #ifndef APIENTRY
  5204. #define APIENTRY
  5205. #endif
  5206. #ifndef APIENTRYP
  5207. #define APIENTRYP APIENTRY*
  5208. #endif
  5209. typedef ptrdiff_t GLsizeiptr;
  5210. #define GL_COMPILE_STATUS 0x8B81
  5211. #define GL_LINK_STATUS 0x8B82
  5212. #define GL_ARRAY_BUFFER 0x8892
  5213. #define GL_STATIC_DRAW 0x88E4
  5214. #define GL_VERTEX_SHADER 0x8B31
  5215. #define GL_FRAGMENT_SHADER 0x8B30
  5216. #define GL_BGRA 0x80E1
  5217. #define GL_TEXTURE0 0x84C0
  5218. typedef void(APIENTRYP PFNGLGENVERTEXARRAYSPROC)(GLsizei n, GLuint* arrays);
  5219. typedef void(APIENTRYP PFNGLGENBUFFERSARBPROC)(GLsizei n, GLuint* buffers);
  5220. typedef void(APIENTRYP PFNGLBINDBUFFERPROC)(GLenum target, GLuint buffer);
  5221. typedef void(APIENTRYP PFNGLBUFFERDATAPROC)(GLenum target, GLsizeiptr size, const void* data, GLenum usage);
  5222. typedef void(APIENTRYP PFNGLBINDVERTEXARRAYPROC)(GLuint array);
  5223. typedef void(APIENTRYP PFNGLENABLEVERTEXATTRIBARRAYPROC)(GLuint index);
  5224. typedef void(APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC)(GLuint index,
  5225. GLint size,
  5226. GLenum type,
  5227. GLboolean normalized,
  5228. GLsizei stride,
  5229. const void* pointer);
  5230. typedef GLuint(APIENTRYP PFNGLCREATESHADERPROC)(GLenum type);
  5231. typedef char GLchar;
  5232. typedef void(APIENTRYP PFNGLSHADERSOURCEPROC)(GLuint shader,
  5233. GLsizei count,
  5234. const GLchar* const* string,
  5235. const GLint* length);
  5236. typedef void(APIENTRYP PFNGLCOMPILESHADERPROC)(GLuint shader);
  5237. typedef GLuint(APIENTRYP PFNGLCREATEPROGRAMPROC)(void);
  5238. typedef void(APIENTRYP PFNGLATTACHSHADERPROC)(GLuint program, GLuint shader);
  5239. typedef void(APIENTRYP PFNGLLINKPROGRAMPROC)(GLuint program);
  5240. typedef void(APIENTRYP PFNGLDELETESHADERPROC)(GLuint shader);
  5241. typedef void(APIENTRYP PFNGLDELETEPROGRAMPROC)(GLuint program);
  5242. typedef void(APIENTRYP PFNGLGETSHADERIVPROC)(GLuint shader, GLenum pname, GLint* params);
  5243. typedef void(APIENTRYP PFNGLGETSHADERINFOLOGPROC)(GLuint shader, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
  5244. typedef void(APIENTRYP PFNGLGETPROGRAMIVPROC)(GLuint program, GLenum pname, GLint* params);
  5245. typedef void(APIENTRYP PFNGLGETPROGRAMINFOLOGPROC)(GLuint program, GLsizei bufSize, GLsizei* length, GLchar* infoLog);
  5246. typedef void(APIENTRYP PFNGLUSEPROGRAMPROC)(GLuint program);
  5247. typedef GLint(APIENTRYP PFNGLGETUNIFORMLOCATIONPROC)(GLuint program, const GLchar* name);
  5248. typedef void(APIENTRYP PFNGLUNIFORM4FPROC)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
  5249. typedef void(APIENTRYP PFNGLUNIFORMMATRIX4FVPROC)(GLint location,
  5250. GLsizei count,
  5251. GLboolean transpose,
  5252. const GLfloat* value);
  5253. typedef void(APIENTRYP PFNGLACTIVETEXTUREPROC)(GLenum texture);
  5254. #define WGL_DRAW_TO_WINDOW_ARB 0x2001
  5255. #define WGL_SUPPORT_OPENGL_ARB 0x2010
  5256. #define WGL_DOUBLE_BUFFER_ARB 0x2011
  5257. #define WGL_PIXEL_TYPE_ARB 0x2013
  5258. #define WGL_COLOR_BITS_ARB 0x2014
  5259. #define WGL_DEPTH_BITS_ARB 0x2022
  5260. #define WGL_STENCIL_BITS_ARB 0x2023
  5261. #define WGL_TYPE_RGBA_ARB 0x202B
  5262. #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
  5263. #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
  5264. typedef BOOL(WINAPI* PFNWGLCHOOSEPIXELFORMATARBPROC)(HDC hdc,
  5265. const int* piAttribIList,
  5266. const FLOAT* pfAttribFList,
  5267. UINT nMaxFormats,
  5268. int* piFormats,
  5269. UINT* nNumFormats);
  5270. typedef HGLRC(WINAPI* PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC hDC, HGLRC hShareContext, const int* attribList);
  5271. #endif
  5272. PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat;
  5273. PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribs;
  5274. PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
  5275. PFNGLGENBUFFERSARBPROC glGenBuffers;
  5276. PFNGLBINDBUFFERPROC glBindBuffer;
  5277. PFNGLBUFFERDATAPROC glBufferData;
  5278. PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
  5279. PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
  5280. PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;
  5281. PFNGLCREATESHADERPROC glCreateShader;
  5282. PFNGLSHADERSOURCEPROC glShaderSource;
  5283. PFNGLCOMPILESHADERPROC glCompileShader;
  5284. PFNGLCREATEPROGRAMPROC glCreateProgram;
  5285. PFNGLATTACHSHADERPROC glAttachShader;
  5286. PFNGLLINKPROGRAMPROC glLinkProgram;
  5287. PFNGLDELETESHADERPROC glDeleteShader;
  5288. PFNGLDELETEPROGRAMPROC glDeleteProgram;
  5289. PFNGLGETSHADERIVPROC glGetShaderiv;
  5290. PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
  5291. PFNGLGETPROGRAMIVPROC glGetProgramiv;
  5292. PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
  5293. PFNGLUSEPROGRAMPROC glUseProgram;
  5294. PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
  5295. PFNGLUNIFORM4FPROC glUniform4f;
  5296. PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
  5297. PFNGLACTIVETEXTUREPROC glActiveTexture;
  5298. int tigrGL11Init(Tigr* bmp) {
  5299. int pixel_format;
  5300. TigrInternal* win = tigrInternal(bmp);
  5301. GLStuff* gl = &win->gl;
  5302. PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR),
  5303. 1,
  5304. PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_SWAP_EXCHANGE,
  5305. PFD_TYPE_RGBA,
  5306. 32, // color bits
  5307. 0,
  5308. 0,
  5309. 0,
  5310. 0,
  5311. 0,
  5312. 0,
  5313. 0,
  5314. 0,
  5315. 0,
  5316. 0,
  5317. 0,
  5318. 0,
  5319. 0,
  5320. 24, // depth
  5321. 8, // stencil
  5322. 0,
  5323. PFD_MAIN_PLANE, // is it ignored ?
  5324. 0,
  5325. 0,
  5326. 0,
  5327. 0 };
  5328. if (!(gl->dc = GetDC((HWND)bmp->handle))) {
  5329. tigrError(bmp, "Cannot create OpenGL device context.\n");
  5330. return -1;
  5331. }
  5332. if (!(pixel_format = ChoosePixelFormat(gl->dc, &pfd))) {
  5333. tigrError(bmp, "Cannot choose OpenGL pixel format.\n");
  5334. return -1;
  5335. }
  5336. if (!SetPixelFormat(gl->dc, pixel_format, &pfd)) {
  5337. tigrError(bmp, "Cannot set OpenGL pixel format.\n");
  5338. return -1;
  5339. }
  5340. if (!(gl->hglrc = wglCreateContext(gl->dc))) {
  5341. tigrError(bmp, "Cannot create OpenGL context.\n");
  5342. return -1;
  5343. }
  5344. if (!wglMakeCurrent(gl->dc, gl->hglrc)) {
  5345. tigrError(bmp, "Cannot activate OpenGL context.\n");
  5346. return -1;
  5347. }
  5348. gl->gl_legacy = 1;
  5349. return 0;
  5350. }
  5351. int tigrGL33Init(Tigr* bmp) {
  5352. int pixel_format;
  5353. UINT num_formats;
  5354. TigrInternal* win = tigrInternal(bmp);
  5355. GLStuff* gl = &win->gl;
  5356. wglChoosePixelFormat = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB");
  5357. wglCreateContextAttribs = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
  5358. glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC)wglGetProcAddress("glGenVertexArrays");
  5359. glGenBuffers = (PFNGLGENBUFFERSARBPROC)wglGetProcAddress("glGenBuffers");
  5360. glBindBuffer = (PFNGLBINDBUFFERPROC)wglGetProcAddress("glBindBuffer");
  5361. glBufferData = (PFNGLBUFFERDATAPROC)wglGetProcAddress("glBufferData");
  5362. glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC)wglGetProcAddress("glBindVertexArray");
  5363. glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC)wglGetProcAddress("glEnableVertexAttribArray");
  5364. glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC)wglGetProcAddress("glVertexAttribPointer");
  5365. glCreateShader = (PFNGLCREATESHADERPROC)wglGetProcAddress("glCreateShader");
  5366. glShaderSource = (PFNGLSHADERSOURCEPROC)wglGetProcAddress("glShaderSource");
  5367. glCompileShader = (PFNGLCOMPILESHADERPROC)wglGetProcAddress("glCompileShader");
  5368. glCreateProgram = (PFNGLCREATEPROGRAMPROC)wglGetProcAddress("glCreateProgram");
  5369. glAttachShader = (PFNGLATTACHSHADERPROC)wglGetProcAddress("glAttachShader");
  5370. glLinkProgram = (PFNGLLINKPROGRAMPROC)wglGetProcAddress("glLinkProgram");
  5371. glDeleteShader = (PFNGLDELETESHADERPROC)wglGetProcAddress("glDeleteShader");
  5372. glDeleteProgram = (PFNGLDELETEPROGRAMPROC)wglGetProcAddress("glDeleteProgram");
  5373. glGetShaderiv = (PFNGLGETSHADERIVPROC)wglGetProcAddress("glGetShaderiv");
  5374. glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC)wglGetProcAddress("glGetShaderInfoLog");
  5375. glGetProgramiv = (PFNGLGETPROGRAMIVPROC)wglGetProcAddress("glGetProgramiv");
  5376. glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC)wglGetProcAddress("glGetProgramInfoLog");
  5377. glUseProgram = (PFNGLUSEPROGRAMPROC)wglGetProcAddress("glUseProgram");
  5378. glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC)wglGetProcAddress("glGetUniformLocation");
  5379. glUniform4f = (PFNGLUNIFORM4FPROC)wglGetProcAddress("glUniform4f");
  5380. glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC)wglGetProcAddress("glUniformMatrix4fv");
  5381. glActiveTexture = (PFNGLACTIVETEXTUREPROC)wglGetProcAddress("glActiveTexture");
  5382. if (!wglChoosePixelFormat || !wglCreateContextAttribs) {
  5383. tigrError(bmp, "Cannot create OpenGL context.\n");
  5384. return -1;
  5385. }
  5386. const int attribList[] = { WGL_DRAW_TO_WINDOW_ARB,
  5387. GL_TRUE,
  5388. WGL_SUPPORT_OPENGL_ARB,
  5389. GL_TRUE,
  5390. WGL_DOUBLE_BUFFER_ARB,
  5391. GL_TRUE,
  5392. WGL_PIXEL_TYPE_ARB,
  5393. WGL_TYPE_RGBA_ARB,
  5394. WGL_COLOR_BITS_ARB,
  5395. 32,
  5396. WGL_DEPTH_BITS_ARB,
  5397. 24,
  5398. WGL_STENCIL_BITS_ARB,
  5399. 8,
  5400. 0 };
  5401. int attribs[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 3, 0 };
  5402. if (!wglChoosePixelFormat(gl->dc, attribList, NULL, 1, &pixel_format, &num_formats)) {
  5403. tigrError(bmp, "Cannot choose OpenGL pixel format.\n");
  5404. return -1;
  5405. }
  5406. if (!(gl->hglrc = wglCreateContextAttribs(gl->dc, gl->hglrc, attribs))) {
  5407. tigrError(bmp, "Cannot create OpenGL context attribs.\n");
  5408. return -1;
  5409. }
  5410. if (!wglMakeCurrent(gl->dc, gl->hglrc)) {
  5411. tigrError(bmp, "Cannot activate OpenGL context.\n");
  5412. return -1;
  5413. }
  5414. gl->gl_legacy = 0;
  5415. return 0;
  5416. }
  5417. #endif
  5418. void tigrCheckGLError(const char* state) {
  5419. GLenum err = glGetError();
  5420. if (err != GL_NO_ERROR) {
  5421. tigrError(NULL, "got GL error %x when doing %s\n", err, state);
  5422. }
  5423. }
  5424. void tigrCheckShaderErrors(GLuint object) {
  5425. GLint success;
  5426. GLchar info[2048];
  5427. glGetShaderiv(object, GL_COMPILE_STATUS, &success);
  5428. if (!success) {
  5429. glGetShaderInfoLog(object, sizeof(info), NULL, info);
  5430. tigrError(NULL, "shader compile error : %s\n", info);
  5431. }
  5432. }
  5433. void tigrCheckProgramErrors(GLuint object) {
  5434. GLint success;
  5435. GLchar info[2048];
  5436. glGetProgramiv(object, GL_LINK_STATUS, &success);
  5437. if (!success) {
  5438. glGetProgramInfoLog(object, sizeof(info), NULL, info);
  5439. tigrError(NULL, "shader link error : %s\n", info);
  5440. }
  5441. }
  5442. void tigrCreateShaderProgram(GLStuff* gl, const char* fxSource, int fxSize) {
  5443. if (gl->program != 0) {
  5444. glDeleteProgram(gl->program);
  5445. gl->program = 0;
  5446. }
  5447. GLuint vs = glCreateShader(GL_VERTEX_SHADER);
  5448. const char* vs_source = (const char*)&tigr_upscale_gl_vs;
  5449. glShaderSource(vs, 1, &vs_source, &tigr_upscale_gl_vs_size);
  5450. glCompileShader(vs);
  5451. tigrCheckShaderErrors(vs);
  5452. GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
  5453. const char* fs_sources[] = {
  5454. (const char*)tigr_upscale_gl_fs,
  5455. fxSource,
  5456. };
  5457. const int fs_lengths[] = {
  5458. tigr_upscale_gl_fs_size,
  5459. fxSize,
  5460. };
  5461. glShaderSource(fs, 2, fs_sources, fs_lengths);
  5462. glCompileShader(fs);
  5463. tigrCheckShaderErrors(fs);
  5464. gl->program = glCreateProgram();
  5465. glAttachShader(gl->program, vs);
  5466. glAttachShader(gl->program, fs);
  5467. glLinkProgram(gl->program);
  5468. tigrCheckProgramErrors(gl->program);
  5469. glDeleteShader(vs);
  5470. glDeleteShader(fs);
  5471. gl->uniform_projection = glGetUniformLocation(gl->program, "projection");
  5472. gl->uniform_model = glGetUniformLocation(gl->program, "model");
  5473. gl->uniform_parameters = glGetUniformLocation(gl->program, "parameters");
  5474. }
  5475. void tigrGAPICreate(Tigr* bmp) {
  5476. TigrInternal* win = tigrInternal(bmp);
  5477. GLStuff* gl = &win->gl;
  5478. GLuint VBO;
  5479. GLfloat vertices[] = { // pos uv
  5480. 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
  5481. 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f
  5482. };
  5483. #ifdef _WIN32
  5484. if (tigrGL11Init(bmp))
  5485. return;
  5486. tigrGL33Init(bmp);
  5487. #endif
  5488. if (!gl->gl_legacy) {
  5489. // create vao
  5490. glGenVertexArrays(1, &gl->vao);
  5491. glGenBuffers(1, &VBO);
  5492. glBindBuffer(GL_ARRAY_BUFFER, VBO);
  5493. glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  5494. glBindVertexArray(gl->vao);
  5495. glEnableVertexAttribArray(0);
  5496. glEnableVertexAttribArray(1);
  5497. glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), NULL);
  5498. glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), NULL);
  5499. // create program
  5500. tigrCreateShaderProgram(gl, tigr_default_fx_gl_fs, tigr_default_fx_gl_fs_size);
  5501. }
  5502. // create textures
  5503. if (gl->gl_legacy) {
  5504. glEnable(GL_TEXTURE_2D);
  5505. }
  5506. glGenTextures(2, gl->tex);
  5507. for (int i = 0; i < 2; ++i) {
  5508. glBindTexture(GL_TEXTURE_2D, gl->tex[i]);
  5509. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl->gl_legacy ? GL_NEAREST : GL_LINEAR);
  5510. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl->gl_legacy ? GL_NEAREST : GL_LINEAR);
  5511. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  5512. glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
  5513. }
  5514. tigrCheckGLError("initialization");
  5515. }
  5516. void tigrGAPIDestroy(Tigr* bmp) {
  5517. TigrInternal* win = tigrInternal(bmp);
  5518. GLStuff* gl = &win->gl;
  5519. if (tigrGAPIBegin(bmp) < 0) {
  5520. tigrError(bmp, "Cannot activate OpenGL context.\n");
  5521. return;
  5522. }
  5523. if (!gl->gl_legacy) {
  5524. glDeleteTextures(2, gl->tex);
  5525. glDeleteProgram(gl->program);
  5526. }
  5527. tigrCheckGLError("destroy");
  5528. if (tigrGAPIEnd(bmp) < 0) {
  5529. tigrError(bmp, "Cannot deactivate OpenGL context.\n");
  5530. return;
  5531. }
  5532. }
  5533. void tigrGAPIDraw(int legacy, GLuint uniform_model, GLuint tex, Tigr* bmp, int x1, int y1, int x2, int y2) {
  5534. glBindTexture(GL_TEXTURE_2D, tex);
  5535. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, bmp->w, bmp->h, 0, GL_RGBA, GL_UNSIGNED_BYTE, bmp->pix);
  5536. if (!legacy) {
  5537. float sx = (float)(x2 - x1);
  5538. float sy = (float)(y2 - y1);
  5539. float tx = (float)x1;
  5540. float ty = (float)y1;
  5541. float model[16] = { sx, 0.0f, 0.0f, 0.0f, 0.0f, sy, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, tx, ty, 0.0f, 1.0f };
  5542. glUniformMatrix4fv(uniform_model, 1, GL_FALSE, model);
  5543. glDrawArrays(GL_TRIANGLES, 0, 6);
  5544. } else {
  5545. #if !(__APPLE__ || __ANDROID__)
  5546. glBegin(GL_QUADS);
  5547. glTexCoord2f(1.0f, 0.0f);
  5548. glVertex2i(x2, y1);
  5549. glTexCoord2f(0.0f, 0.0f);
  5550. glVertex2i(x1, y1);
  5551. glTexCoord2f(0.0f, 1.0f);
  5552. glVertex2i(x1, y2);
  5553. glTexCoord2f(1.0f, 1.0f);
  5554. glVertex2i(x2, y2);
  5555. glEnd();
  5556. #else
  5557. assert(0);
  5558. #endif
  5559. }
  5560. }
  5561. void tigrGAPIPresent(Tigr* bmp, int w, int h) {
  5562. TigrInternal* win = tigrInternal(bmp);
  5563. GLStuff* gl = &win->gl;
  5564. glViewport(0, 0, w, h);
  5565. if (!gl->gl_user_opengl_rendering) {
  5566. glClearColor(0, 0, 0, 1);
  5567. glClear(GL_COLOR_BUFFER_BIT);
  5568. }
  5569. if (!gl->gl_legacy) {
  5570. float projection[16] = { 2.0f / w, 0.0f, 0.0f, 0.0f, 0.0f, -2.0f / h, 0.0f, 0.0f,
  5571. 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, 0.0f, 1.0f };
  5572. glActiveTexture(GL_TEXTURE0);
  5573. glBindVertexArray(gl->vao);
  5574. glUseProgram(gl->program);
  5575. glUniformMatrix4fv(gl->uniform_projection, 1, GL_FALSE, projection);
  5576. glUniform4f(gl->uniform_parameters, win->p1, win->p2, win->p3, win->p4);
  5577. } else {
  5578. #if !(__APPLE__ || __ANDROID__)
  5579. glMatrixMode(GL_PROJECTION);
  5580. glLoadIdentity();
  5581. glOrtho(0, w, h, 0, -1.0f, 1.0f);
  5582. glEnable(GL_TEXTURE_2D);
  5583. #else
  5584. assert(0);
  5585. #endif
  5586. }
  5587. if (gl->gl_user_opengl_rendering) {
  5588. glEnable(GL_BLEND);
  5589. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  5590. } else {
  5591. glDisable(GL_BLEND);
  5592. }
  5593. tigrGAPIDraw(gl->gl_legacy, gl->uniform_model, gl->tex[0], bmp, win->pos[0], win->pos[1], win->pos[2], win->pos[3]);
  5594. if (win->widgetsScale > 0) {
  5595. glEnable(GL_BLEND);
  5596. glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  5597. tigrGAPIDraw(gl->gl_legacy, gl->uniform_model, gl->tex[1], win->widgets,
  5598. (int)(w - win->widgets->w * win->widgetsScale), 0, w, (int)(win->widgets->h * win->widgetsScale));
  5599. }
  5600. tigrCheckGLError("present");
  5601. gl->gl_user_opengl_rendering = 0;
  5602. }
  5603. #endif
  5604. #endif // #ifndef TIGR_HEADLESS
  5605. //////// End of inlined file: tigr_gl.c ////////
  5606. //////// Start of inlined file: tigr_utils.c ////////
  5607. //#include "tigr_internal.h"
  5608. #include <stdio.h>
  5609. #include <stdlib.h>
  5610. #ifndef __ANDROID__
  5611. #ifdef __IOS__
  5612. void* _tigrReadFile(const char* fileName, int* length) {
  5613. #else
  5614. void* tigrReadFile(const char* fileName, int* length) {
  5615. #endif
  5616. // TODO - unicode?
  5617. FILE* file;
  5618. char* data;
  5619. size_t len;
  5620. if (length)
  5621. *length = 0;
  5622. file = fopen(fileName, "rb");
  5623. if (!file)
  5624. return NULL;
  5625. fseek(file, 0, SEEK_END);
  5626. len = ftell(file);
  5627. fseek(file, 0, SEEK_SET);
  5628. data = (char*)malloc(len + 1);
  5629. if (!data) {
  5630. fclose(file);
  5631. return NULL;
  5632. }
  5633. if (fread(data, 1, len, file) != len) {
  5634. free(data);
  5635. fclose(file);
  5636. return NULL;
  5637. }
  5638. data[len] = '\0';
  5639. fclose(file);
  5640. if (length)
  5641. *length = len;
  5642. return data;
  5643. }
  5644. #endif // __ANDROID__
  5645. // Reads a single UTF8 codepoint.
  5646. const char* tigrDecodeUTF8(const char* text, int* cp) {
  5647. unsigned char c = *text++;
  5648. int extra = 0, min = 0;
  5649. *cp = 0;
  5650. if (c >= 0xf0) {
  5651. *cp = c & 0x07;
  5652. extra = 3;
  5653. min = 0x10000;
  5654. } else if (c >= 0xe0) {
  5655. *cp = c & 0x0f;
  5656. extra = 2;
  5657. min = 0x800;
  5658. } else if (c >= 0xc0) {
  5659. *cp = c & 0x1f;
  5660. extra = 1;
  5661. min = 0x80;
  5662. } else if (c >= 0x80) {
  5663. *cp = 0xfffd;
  5664. } else {
  5665. *cp = c;
  5666. }
  5667. while (extra--) {
  5668. c = *text++;
  5669. if ((c & 0xc0) != 0x80) {
  5670. *cp = 0xfffd;
  5671. break;
  5672. }
  5673. (*cp) = ((*cp) << 6) | (c & 0x3f);
  5674. }
  5675. if (*cp < min) {
  5676. *cp = 0xfffd;
  5677. }
  5678. return text;
  5679. }
  5680. char* tigrEncodeUTF8(char* text, int cp) {
  5681. if (cp < 0 || cp > 0x10ffff) {
  5682. cp = 0xfffd;
  5683. }
  5684. #define EMIT(X, Y, Z) *text++ = X | ((cp >> Y) & Z)
  5685. if (cp < 0x80) {
  5686. EMIT(0x00, 0, 0x7f);
  5687. } else if (cp < 0x800) {
  5688. EMIT(0xc0, 6, 0x1f);
  5689. EMIT(0x80, 0, 0x3f);
  5690. } else if (cp < 0x10000) {
  5691. EMIT(0xe0, 12, 0xf);
  5692. EMIT(0x80, 6, 0x3f);
  5693. EMIT(0x80, 0, 0x3f);
  5694. } else {
  5695. EMIT(0xf0, 18, 0x7);
  5696. EMIT(0x80, 12, 0x3f);
  5697. EMIT(0x80, 6, 0x3f);
  5698. EMIT(0x80, 0, 0x3f);
  5699. }
  5700. return text;
  5701. #undef EMIT
  5702. }
  5703. #ifndef TIGR_HEADLESS
  5704. int tigrBeginOpenGL(Tigr* bmp) {
  5705. #ifdef TIGR_GAPI_GL
  5706. TigrInternal* win = tigrInternal(bmp);
  5707. win->gl.gl_user_opengl_rendering = 1;
  5708. return tigrGAPIBegin(bmp) == 0;
  5709. #else
  5710. return 0;
  5711. #endif
  5712. }
  5713. void tigrSetPostShader(Tigr* bmp, const char* code, int size) {
  5714. #ifdef TIGR_GAPI_GL
  5715. tigrGAPIBegin(bmp);
  5716. TigrInternal* win = tigrInternal(bmp);
  5717. GLStuff* gl = &win->gl;
  5718. tigrCreateShaderProgram(gl, code, size);
  5719. tigrGAPIEnd(bmp);
  5720. #endif
  5721. }
  5722. void tigrSetPostFX(Tigr* bmp, float p1, float p2, float p3, float p4) {
  5723. TigrInternal* win = tigrInternal(bmp);
  5724. win->p1 = p1;
  5725. win->p2 = p2;
  5726. win->p3 = p3;
  5727. win->p4 = p4;
  5728. }
  5729. #endif // TIGR_HEADLESS
  5730. //////// End of inlined file: tigr_utils.c ////////
  5731. //////// End of inlined file: tigr_amalgamated.c ////////