sokol_app.h 285 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590
  1. #ifndef SOKOL_APP_INCLUDED
  2. /*
  3. sokol_app.h -- cross-platform application wrapper
  4. Project URL: https://github.com/floooh/sokol
  5. Do this:
  6. #define SOKOL_IMPL
  7. before you include this file in *one* C or C++ file to create the
  8. implementation.
  9. Optionally provide the following defines with your own implementations:
  10. SOKOL_ASSERT(c) - your own assert macro (default: assert(c))
  11. SOKOL_LOG(msg) - your own logging function (default: puts(msg))
  12. SOKOL_UNREACHABLE() - a guard macro for unreachable code (default: assert(false))
  13. SOKOL_ABORT() - called after an unrecoverable error (default: abort())
  14. SOKOL_WIN32_FORCE_MAIN - define this on Win32 to use a main() entry point instead of WinMain
  15. SOKOL_NO_ENTRY - define this if sokol_app.h shouldn't "hijack" the main() function
  16. SOKOL_API_DECL - public function declaration prefix (default: extern)
  17. SOKOL_API_IMPL - public function implementation prefix (default: -)
  18. SOKOL_CALLOC - your own calloc function (default: calloc(n, s))
  19. SOKOL_FREE - your own free function (default: free(p))
  20. Optionally define the following to force debug checks and validations
  21. even in release mode:
  22. SOKOL_DEBUG - by default this is defined if _DEBUG is defined
  23. If sokol_app.h is compiled as a DLL, define the following before
  24. including the declaration or implementation:
  25. SOKOL_DLL
  26. On Windows, SOKOL_DLL will define SOKOL_API_DECL as __declspec(dllexport)
  27. or __declspec(dllimport) as needed.
  28. Portions of the Windows and Linux GL initialization and event code have been
  29. taken from GLFW (http://www.glfw.org/)
  30. iOS onscreen keyboard support 'inspired' by libgdx.
  31. If you use sokol_app.h together with sokol_gfx.h, include both headers
  32. in the implementation source file, and include sokol_app.h before
  33. sokol_gfx.h since sokol_app.h will also include the required 3D-API
  34. headers.
  35. On Windows, a minimal 'GL header' and function loader is integrated which
  36. contains just enough of GL for sokol_gfx.h. If you want to use your own
  37. GL header-generator/loader instead, define SOKOL_WIN32_NO_GL_LOADER
  38. before including the implementation part of sokol_app.h.
  39. For example code, see https://github.com/floooh/sokol-samples/tree/master/sapp
  40. FEATURE OVERVIEW
  41. ================
  42. sokol_app.h provides a minimalistic cross-platform API which
  43. implements the 'application-wrapper' parts of a 3D application:
  44. - a common application entry function
  45. - creates a window and 3D-API context/device with a 'default framebuffer'
  46. - makes the rendered frame visible
  47. - provides keyboard-, mouse- and low-level touch-events
  48. - platforms: MacOS, iOS, HTML5, Win32, Linux, Android (TODO: RaspberryPi)
  49. - 3D-APIs: Metal, D3D11, GL3.2, GLES2, GLES3, WebGL, WebGL2
  50. FEATURE/PLATFORM MATRIX
  51. =======================
  52. | Windows | macOS | Linux | iOS | Android | Raspi | HTML5
  53. --------------------+---------+-------+-------+-------+---------+-------+-------
  54. gl 3.x | YES | YES | YES | --- | --- | --- | ---
  55. gles2/webgl | --- | --- | --- | YES | YES | TODO | YES
  56. gles3/webgl2 | --- | --- | --- | YES | YES | --- | YES
  57. metal | --- | YES | --- | YES | --- | --- | ---
  58. d3d11 | YES | --- | --- | --- | --- | --- | ---
  59. KEY_DOWN | YES | YES | YES | SOME | TODO | TODO | YES
  60. KEY_UP | YES | YES | YES | SOME | TODO | TODO | YES
  61. CHAR | YES | YES | YES | YES | TODO | TODO | YES
  62. MOUSE_DOWN | YES | YES | YES | --- | --- | TODO | YES
  63. MOUSE_UP | YES | YES | YES | --- | --- | TODO | YES
  64. MOUSE_SCROLL | YES | YES | YES | --- | --- | TODO | YES
  65. MOUSE_MOVE | YES | YES | YES | --- | --- | TODO | YES
  66. MOUSE_ENTER | YES | YES | YES | --- | --- | TODO | YES
  67. MOUSE_LEAVE | YES | YES | YES | --- | --- | TODO | YES
  68. TOUCHES_BEGAN | --- | --- | --- | YES | YES | --- | YES
  69. TOUCHES_MOVED | --- | --- | --- | YES | YES | --- | YES
  70. TOUCHES_ENDED | --- | --- | --- | YES | YES | --- | YES
  71. TOUCHES_CANCELLED | --- | --- | --- | YES | YES | --- | YES
  72. RESIZED | YES | YES | YES | YES | YES | --- | YES
  73. ICONIFIED | YES | YES | YES | --- | --- | --- | ---
  74. RESTORED | YES | YES | YES | --- | --- | --- | ---
  75. SUSPENDED | --- | --- | --- | YES | YES | --- | TODO
  76. RESUMED | --- | --- | --- | YES | YES | --- | TODO
  77. QUIT_REQUESTED | YES | YES | YES | --- | --- | TODO | ---
  78. UPDATE_CURSOR | YES | YES | TODO | --- | --- | --- | TODO
  79. IME | TODO | TODO? | TODO | ??? | TODO | ??? | ???
  80. key repeat flag | YES | YES | YES | --- | --- | TODO | YES
  81. windowed | YES | YES | YES | --- | --- | TODO | YES
  82. fullscreen | YES | YES | TODO | YES | YES | TODO | ---
  83. pointer lock | TODO | TODO | TODO | --- | --- | TODO | TODO
  84. screen keyboard | --- | --- | --- | YES | TODO | --- | YES
  85. swap interval | YES | YES | YES | YES | TODO | TODO | YES
  86. high-dpi | YES | YES | TODO | YES | YES | TODO | YES
  87. clipboard | YES | YES | TODO | --- | --- | --- | YES
  88. TODO
  89. ====
  90. - Linux clipboard support
  91. - sapp_consume_event() on non-web platforms?
  92. STEP BY STEP
  93. ============
  94. --- Add a sokol_main() function to your code which returns a sapp_desc structure
  95. with initialization parameters and callback function pointers. This
  96. function is called very early, usually at the start of the
  97. platform's entry function (e.g. main or WinMain). You should do as
  98. little as possible here, since the rest of your code might be called
  99. from another thread (this depends on the platform):
  100. sapp_desc sokol_main(int argc, char* argv[]) {
  101. return (sapp_desc) {
  102. .width = 640,
  103. .height = 480,
  104. .init_cb = my_init_func,
  105. .frame_cb = my_frame_func,
  106. .cleanup_cb = my_cleanup_func,
  107. .event_cb = my_event_func,
  108. ...
  109. };
  110. }
  111. There are many more setup parameters, but these are the most important.
  112. For a complete list search for the sapp_desc structure declaration
  113. below.
  114. DO NOT call any sokol-app function from inside sokol_main(), since
  115. sokol-app will not be initialized at this point.
  116. The .width and .height parameters are the preferred size of the 3D
  117. rendering canvas. The actual size may differ from this depending on
  118. platform and other circumstances. Also the canvas size may change at
  119. any time (for instance when the user resizes the application window,
  120. or rotates the mobile device).
  121. All provided function callbacks will be called from the same thread,
  122. but this may be different from the thread where sokol_main() was called.
  123. .init_cb (void (*)(void))
  124. This function is called once after the application window,
  125. 3D rendering context and swap chain have been created. The
  126. function takes no arguments and has no return value.
  127. .frame_cb (void (*)(void))
  128. This is the per-frame callback, which is usually called 60
  129. times per second. This is where your application would update
  130. most of its state and perform all rendering.
  131. .cleanup_cb (void (*)(void))
  132. The cleanup callback is called once right before the application
  133. quits.
  134. .event_cb (void (*)(const sapp_event* event))
  135. The event callback is mainly for input handling, but in the
  136. future may also be used to communicate other types of events
  137. to the application. Keep the event_cb struct member zero-initialized
  138. if your application doesn't require event handling.
  139. .fail_cb (void (*)(const char* msg))
  140. The fail callback is called when a fatal error is encountered
  141. during start which doesn't allow the program to continue.
  142. Providing a callback here gives you a chance to show an error message
  143. to the user. The default behaviour is SOKOL_LOG(msg)
  144. As you can see, those 'standard callbacks' don't have a user_data
  145. argument, so any data that needs to be preserved between callbacks
  146. must live in global variables. If you're allergic to global variables
  147. or cannot use them for other reasons, an alternative set of callbacks
  148. can be defined in sapp_desc, together with a user_data pointer:
  149. .user_data (void*)
  150. The user-data argument for the callbacks below
  151. .init_userdata_cb (void (*)(void* user_data))
  152. .frame_userdata_cb (void (*)(void* user_data))
  153. .cleanup_userdata_cb (void (*)(void* user_data))
  154. .event_cb (void(*)(const sapp_event* event, void* user_data))
  155. .fail_cb (void(*)(const char* msg, void* user_data))
  156. These are the user-data versions of the callback functions. You
  157. can mix those with the standard callbacks that don't have the
  158. user_data argument.
  159. The function sapp_userdata() can be used to query the user_data
  160. pointer provided in the sapp_desc struct.
  161. You can call sapp_query_desc() to get a copy of the
  162. original sapp_desc structure.
  163. NOTE that there's also an alternative compile mode where sokol_app.h
  164. doesn't "hijack" the main() function. Search below for SOKOL_NO_ENTRY.
  165. --- Implement the initialization callback function (init_cb), this is called
  166. once after the rendering surface, 3D API and swap chain have been
  167. initialized by sokol_app. All sokol-app functions can be called
  168. from inside the initialization callback, the most useful functions
  169. at this point are:
  170. int sapp_width(void)
  171. Returns the current width of the default framebuffer, this may change
  172. from one frame to the next.
  173. int sapp_height(void)
  174. Likewise, returns the current height of the default framebuffer.
  175. bool sapp_gles2(void)
  176. Returns true if a GLES2 or WebGL context has been created. This
  177. is useful when a GLES3/WebGL2 context was requested but is not
  178. available so that sokol_app.h had to fallback to GLES2/WebGL.
  179. const void* sapp_metal_get_device(void)
  180. const void* sapp_metal_get_renderpass_descriptor(void)
  181. const void* sapp_metal_get_drawable(void)
  182. If the Metal backend has been selected, these functions return pointers
  183. to various Metal API objects required for rendering, otherwise
  184. they return a null pointer. These void pointers are actually
  185. Objective-C ids converted with an ARC __bridge cast so that
  186. they ids can be tunnel through C code. Also note that the returned
  187. pointers to the renderpass-descriptor and drawable may change from one
  188. frame to the next, only the Metal device object is guaranteed to
  189. stay the same.
  190. const void* sapp_macos_get_window(void)
  191. On macOS, get the NSWindow object pointer, otherwise a null pointer.
  192. Before being used as Objective-C object, the void* must be converted
  193. back with an ARC __bridge cast.
  194. const void* sapp_ios_get_window(void)
  195. On iOS, get the UIWindow object pointer, otherwise a null pointer.
  196. Before being used as Objective-C object, the void* must be converted
  197. back with an ARC __bridge cast.
  198. const void* sapp_win32_get_hwnd(void)
  199. On Windows, get the window's HWND, otherwise a null pointer. The
  200. HWND has been cast to a void pointer in order to be tunneled
  201. through code which doesn't include Windows.h.
  202. const void* sapp_d3d11_get_device(void);
  203. const void* sapp_d3d11_get_device_context(void);
  204. const void* sapp_d3d11_get_render_target_view(void);
  205. const void* sapp_d3d11_get_depth_stencil_view(void);
  206. Similar to the sapp_metal_* functions, the sapp_d3d11_* functions
  207. return pointers to D3D11 API objects required for rendering,
  208. only if the D3D11 backend has been selected. Otherwise they
  209. return a null pointer. Note that the returned pointers to the
  210. render-target-view and depth-stencil-view may change from one
  211. frame to the next!
  212. const void* sapp_android_get_native_activity(void);
  213. On Android, get the native activity ANativeActivity pointer, otherwise
  214. a null pointer.
  215. --- Implement the frame-callback function, this function will be called
  216. on the same thread as the init callback, but might be on a different
  217. thread than the sokol_main() function. Note that the size of
  218. the rendering framebuffer might have changed since the frame callback
  219. was called last. Call the functions sapp_width() and sapp_height()
  220. each frame to get the current size.
  221. --- Optionally implement the event-callback to handle input events.
  222. sokol-app provides the following type of input events:
  223. - a 'virtual key' was pressed down or released
  224. - a single text character was entered (provided as UTF-32 code point)
  225. - a mouse button was pressed down or released (left, right, middle)
  226. - mouse-wheel or 2D scrolling events
  227. - the mouse was moved
  228. - the mouse has entered or left the application window boundaries
  229. - low-level, portable multi-touch events (began, moved, ended, cancelled)
  230. - the application window was resized, iconified or restored
  231. - the application was suspended or restored (on mobile platforms)
  232. - the user or application code has asked to quit the application
  233. - a string was pasted to the system clipboard
  234. To explicitly 'consume' an event and prevent that the event is
  235. forwarded for further handling to the operating system, call
  236. sapp_consume_event() from inside the event handler (NOTE that
  237. this behaviour is currently only implemented for some HTML5
  238. events, support for other platforms and event types will
  239. be added as needed, please open a github ticket and/or provide
  240. a PR if needed).
  241. NOTE: Do *not* call any 3D API functions in the event callback
  242. function, since the 3D API context may not be active when the
  243. event callback is called (it may work on some platforms and
  244. 3D APIs, but not others, and the exact behaviour may change
  245. between sokol-app versions).
  246. --- Implement the cleanup-callback function, this is called once
  247. after the user quits the application (see the section
  248. "APPLICATION QUIT" for detailed information on quitting
  249. behaviour, and how to intercept a pending quit (for instance to show a
  250. "Really Quit?" dialog box). Note that the cleanup-callback isn't
  251. called on the web and mobile platforms.
  252. CLIPBOARD SUPPORT
  253. =================
  254. Applications can send and receive UTF-8 encoded text data from and to the
  255. system clipboard. By default, clipboard support is disabled and
  256. must be enabled at startup via the following sapp_desc struct
  257. members:
  258. sapp_desc.enable_clipboard - set to true to enable clipboard support
  259. sapp_desc.clipboard_size - size of the internal clipboard buffer in bytes
  260. Enabling the clipboard will dynamically allocate a clipboard buffer
  261. for UTF-8 encoded text data of the requested size in bytes, the default
  262. size if 8 KBytes. Strings that don't fit into the clipboard buffer
  263. (including the terminating zero) will be silently clipped, so it's
  264. important that you provide a big enough clipboard size for your
  265. use case.
  266. To send data to the clipboard, call sapp_set_clipboard_string() with
  267. a pointer to an UTF-8 encoded, null-terminated C-string.
  268. NOTE that on the HTML5 platform, sapp_set_clipboard_string() must be
  269. called from inside a 'short-lived event handler', and there are a few
  270. other HTML5-specific caveats to workaround. You'll basically have to
  271. tinker until it works in all browsers :/ (maybe the situation will
  272. improve when all browsers agree on and implement the new
  273. HTML5 navigator.clipboard API).
  274. To get data from the clipboard, check for the SAPP_EVENTTYPE_CLIPBOARD_PASTED
  275. event in your event handler function, and then call sapp_get_clipboard_string()
  276. to obtain the updated UTF-8 encoded text.
  277. NOTE that behaviour of sapp_get_clipboard_string() is slightly different
  278. depending on platform:
  279. - on the HTML5 platform, the internal clipboard buffer will only be updated
  280. right before the SAPP_EVENTTYPE_CLIPBOARD_PASTED event is sent,
  281. and sapp_get_clipboard_string() will simply return the current content
  282. of the clipboard buffer
  283. - on 'native' platforms, the call to sapp_get_clipboard_string() will
  284. update the internal clipboard buffer with the most recent data
  285. from the system clipboard
  286. Portable code should check for the SAPP_EVENTTYPE_CLIPBOARD_PASTED event,
  287. and then call sapp_get_clipboard_string() right in the event handler.
  288. The SAPP_EVENTTYPE_CLIPBOARD_PASTED event will be generated by sokol-app
  289. as follows:
  290. - on macOS: when the Cmd+V key is pressed down
  291. - on HTML5: when the browser sends a 'paste' event to the global 'window' object
  292. - on all other platforms: when the Ctrl+V key is pressed down
  293. HIGH-DPI RENDERING
  294. ==================
  295. You can set the sapp_desc.high_dpi flag during initialization to request
  296. a full-resolution framebuffer on HighDPI displays. The default behaviour
  297. is sapp_desc.high_dpi=false, this means that the application will
  298. render to a lower-resolution framebuffer on HighDPI displays and the
  299. rendered content will be upscaled by the window system composer.
  300. In a HighDPI scenario, you still request the same window size during
  301. sokol_main(), but the framebuffer sizes returned by sapp_width()
  302. and sapp_height() will be scaled up according to the DPI scaling
  303. ratio. You can also get a DPI scaling factor with the function
  304. sapp_dpi_scale().
  305. Here's an example on a Mac with Retina display:
  306. sapp_desc sokol_main() {
  307. return (sapp_desc) {
  308. .width = 640,
  309. .height = 480,
  310. .high_dpi = true,
  311. ...
  312. };
  313. }
  314. The functions sapp_width(), sapp_height() and sapp_dpi_scale() will
  315. return the following values:
  316. sapp_width -> 1280
  317. sapp_height -> 960
  318. sapp_dpi_scale -> 2.0
  319. If the high_dpi flag is false, or you're not running on a Retina display,
  320. the values would be:
  321. sapp_width -> 640
  322. sapp_height -> 480
  323. sapp_dpi_scale -> 1.0
  324. APPLICATION QUIT
  325. ================
  326. Without special quit handling, a sokol_app.h application will exist
  327. 'gracefully' when the user clicks the window close-button. 'Graceful
  328. exit' means that the application-provided cleanup callback will be
  329. called.
  330. This 'graceful exit' is only supported on native desktop platforms, on
  331. the web and mobile platforms an application may be terminated at any time
  332. by the user or browser/OS runtime environment without a chance to run
  333. custom shutdown code.
  334. On the web platform, you can call the following function to let the
  335. browser open a standard popup dialog before the user wants to leave a site:
  336. sapp_html5_ask_leave_site(bool ask);
  337. The initial state of the associated internal flag can be provided
  338. at startup via sapp_desc.html5_ask_leave_site.
  339. This feature should only be used sparingly in critical situations - for
  340. instance when the user would loose data - since popping up modal dialog
  341. boxes is considered quite rude in the web world. Note that there's no way
  342. to customize the content of this dialog box or run any code as a result
  343. of the user's decision. Also note that the user must have interacted with
  344. the site before the dialog box will appear. These are all security measures
  345. to prevent fishing.
  346. On native desktop platforms, sokol_app.h provides more control over the
  347. application-quit-process. It's possible to initiate a 'programmatic quit'
  348. from the application code, and a quit initiated by the application user
  349. can be intercepted (for instance to show a custom dialog box).
  350. This 'programmatic quit protocol' is implemented trough 3 functions
  351. and 1 event:
  352. - sapp_quit(): This function simply quits the application without
  353. giving the user a chance to intervene. Usually this might
  354. be called when the user clicks the 'Ok' button in a 'Really Quit?'
  355. dialog box
  356. - sapp_request_quit(): Calling sapp_request_quit() will send the
  357. event SAPP_EVENTTYPE_QUIT_REQUESTED to the applications event handler
  358. callback, giving the user code a chance to intervene and cancel the
  359. pending quit process (for instance to show a 'Really Quit?' dialog
  360. box). If the event handler callback does nothing, the application
  361. will be quit as usual. To prevent this, call the function
  362. sapp_cancel_quit() from inside the event handler.
  363. - sapp_cancel_quit(): Cancels a pending quit request, either initiated
  364. by the user clicking the window close button, or programmatically
  365. by calling sapp_request_quit(). The only place where calling this
  366. function makes sense is from inside the event handler callback when
  367. the SAPP_EVENTTYPE_QUIT_REQUESTED event has been received.
  368. - SAPP_EVENTTYPE_QUIT_REQUESTED: this event is sent when the user
  369. clicks the window's close button or application code calls the
  370. sapp_request_quit() function. The event handler callback code can handle
  371. this event by calling sapp_cancel_quit() to cancel the quit.
  372. If the event is ignored, the application will quit as usual.
  373. The Dear ImGui HighDPI sample contains example code of how to
  374. implement a 'Really Quit?' dialog box with Dear ImGui (native desktop
  375. platforms only), and for showing the hardwired "Leave Site?" dialog box
  376. when running on the web platform:
  377. https://floooh.github.io/sokol-html5/wasm/imgui-highdpi-sapp.html
  378. FULLSCREEN
  379. ==========
  380. If the sapp_desc.fullscreen flag is true, sokol-app will try to create
  381. a fullscreen window on platforms with a 'proper' window system
  382. (mobile devices will always use fullscreen). The implementation details
  383. depend on the target platform, in general sokol-app will use a
  384. 'soft approach' which doesn't interfere too much with the platform's
  385. window system (for instance borderless fullscreen window instead of
  386. a 'real' fullscreen mode). Such details might change over time
  387. as sokol-app is adapted for different needs.
  388. The most important effect of fullscreen mode to keep in mind is that
  389. the requested canvas width and height will be ignored for the initial
  390. window size, calling sapp_width() and sapp_height() will instead return
  391. the resolution of the fullscreen canvas (however the provided size
  392. might still be used for the non-fullscreen window, in case the user can
  393. switch back from fullscreen- to windowed-mode).
  394. ONSCREEN KEYBOARD
  395. =================
  396. On some platforms which don't provide a physical keyboard, sokol-app
  397. can display the platform's integrated onscreen keyboard for text
  398. input. To request that the onscreen keyboard is shown, call
  399. sapp_show_keyboard(true);
  400. Likewise, to hide the keyboard call:
  401. sapp_show_keyboard(false);
  402. Note that on the web platform, the keyboard can only be shown from
  403. inside an input handler. On such platforms, sapp_show_keyboard()
  404. will only work as expected when it is called from inside the
  405. sokol-app event callback function. When called from other places,
  406. an internal flag will be set, and the onscreen keyboard will be
  407. called at the next 'legal' opportunity (when the next input event
  408. is handled).
  409. OPTIONAL: DON'T HIJACK main() (#define SOKOL_NO_ENTRY)
  410. ======================================================
  411. In its default configuration, sokol_app.h "hijacks" the platform's
  412. standard main() function. This was done because different platforms
  413. have different main functions which are not compatible with
  414. C's main() (for instance WinMain on Windows has completely different
  415. arguments). However, this "main hijacking" posed a problem for
  416. usage scenarios like integrating sokol_app.h with other languages than
  417. C or C++, so an alternative SOKOL_NO_ENTRY mode has been added
  418. in which the user code provides the platform's main function:
  419. - define SOKOL_NO_ENTRY before including the sokol_app.h implementation
  420. - do *not* provide a sokol_main() function
  421. - instead provide the standard main() function of the platform
  422. - from the main function, call the function ```sapp_run()``` which
  423. takes a pointer to an ```sapp_desc``` structure.
  424. - ```sapp_run()``` takes over control and calls the provided init-, frame-,
  425. shutdown- and event-callbacks just like in the default model, it
  426. will only return when the application quits (or not at all on some
  427. platforms, like emscripten)
  428. NOTE: SOKOL_NO_ENTRY is currently not supported on Android.
  429. TEMP NOTE DUMP
  430. ==============
  431. - onscreen keyboard support on Android requires Java :(, should we even bother?
  432. - sapp_desc needs a bool whether to initialize depth-stencil surface
  433. - GL context initialization needs more control (at least what GL version to initialize)
  434. - application icon
  435. - mouse pointer visibility(?)
  436. - the UPDATE_CURSOR event currently behaves differently between Win32 and OSX
  437. (Win32 sends the event each frame when the mouse moves and is inside the window
  438. client area, OSX sends it only once when the mouse enters the client area)
  439. - the Android implementation calls cleanup_cb() and destroys the egl context in onDestroy
  440. at the latest but should do it earlier, in onStop, as an app is "killable" after onStop
  441. on Android Honeycomb and later (it can't be done at the moment as the app may be started
  442. again after onStop and the sokol lifecycle does not yet handle context teardown/bringup)
  443. FIXME: ERROR HANDLING (this will need an error callback function)
  444. zlib/libpng license
  445. Copyright (c) 2018 Andre Weissflog
  446. This software is provided 'as-is', without any express or implied warranty.
  447. In no event will the authors be held liable for any damages arising from the
  448. use of this software.
  449. Permission is granted to anyone to use this software for any purpose,
  450. including commercial applications, and to alter it and redistribute it
  451. freely, subject to the following restrictions:
  452. 1. The origin of this software must not be misrepresented; you must not
  453. claim that you wrote the original software. If you use this software in a
  454. product, an acknowledgment in the product documentation would be
  455. appreciated but is not required.
  456. 2. Altered source versions must be plainly marked as such, and must not
  457. be misrepresented as being the original software.
  458. 3. This notice may not be removed or altered from any source
  459. distribution.
  460. */
  461. #define SOKOL_APP_INCLUDED (1)
  462. #include <stdint.h>
  463. #include <stdbool.h>
  464. #ifndef SOKOL_API_DECL
  465. #if defined(_WIN32) && defined(SOKOL_DLL) && defined(SOKOL_IMPL)
  466. #define SOKOL_API_DECL __declspec(dllexport)
  467. #elif defined(_WIN32) && defined(SOKOL_DLL)
  468. #define SOKOL_API_DECL __declspec(dllimport)
  469. #else
  470. #define SOKOL_API_DECL extern
  471. #endif
  472. #endif
  473. #ifdef __cplusplus
  474. extern "C" {
  475. #endif
  476. enum {
  477. SAPP_MAX_TOUCHPOINTS = 8,
  478. SAPP_MAX_MOUSEBUTTONS = 3,
  479. SAPP_MAX_KEYCODES = 512,
  480. };
  481. typedef enum sapp_event_type {
  482. SAPP_EVENTTYPE_INVALID,
  483. SAPP_EVENTTYPE_KEY_DOWN,
  484. SAPP_EVENTTYPE_KEY_UP,
  485. SAPP_EVENTTYPE_CHAR,
  486. SAPP_EVENTTYPE_MOUSE_DOWN,
  487. SAPP_EVENTTYPE_MOUSE_UP,
  488. SAPP_EVENTTYPE_MOUSE_SCROLL,
  489. SAPP_EVENTTYPE_MOUSE_MOVE,
  490. SAPP_EVENTTYPE_MOUSE_ENTER,
  491. SAPP_EVENTTYPE_MOUSE_LEAVE,
  492. SAPP_EVENTTYPE_TOUCHES_BEGAN,
  493. SAPP_EVENTTYPE_TOUCHES_MOVED,
  494. SAPP_EVENTTYPE_TOUCHES_ENDED,
  495. SAPP_EVENTTYPE_TOUCHES_CANCELLED,
  496. SAPP_EVENTTYPE_RESIZED,
  497. SAPP_EVENTTYPE_ICONIFIED,
  498. SAPP_EVENTTYPE_RESTORED,
  499. SAPP_EVENTTYPE_SUSPENDED,
  500. SAPP_EVENTTYPE_RESUMED,
  501. SAPP_EVENTTYPE_UPDATE_CURSOR,
  502. SAPP_EVENTTYPE_QUIT_REQUESTED,
  503. SAPP_EVENTTYPE_CLIPBOARD_PASTED,
  504. _SAPP_EVENTTYPE_NUM,
  505. _SAPP_EVENTTYPE_FORCE_U32 = 0x7FFFFFFF
  506. } sapp_event_type;
  507. /* key codes are the same names and values as GLFW */
  508. typedef enum sapp_keycode {
  509. SAPP_KEYCODE_INVALID = 0,
  510. SAPP_KEYCODE_SPACE = 32,
  511. SAPP_KEYCODE_APOSTROPHE = 39, /* ' */
  512. SAPP_KEYCODE_COMMA = 44, /* , */
  513. SAPP_KEYCODE_MINUS = 45, /* - */
  514. SAPP_KEYCODE_PERIOD = 46, /* . */
  515. SAPP_KEYCODE_SLASH = 47, /* / */
  516. SAPP_KEYCODE_0 = 48,
  517. SAPP_KEYCODE_1 = 49,
  518. SAPP_KEYCODE_2 = 50,
  519. SAPP_KEYCODE_3 = 51,
  520. SAPP_KEYCODE_4 = 52,
  521. SAPP_KEYCODE_5 = 53,
  522. SAPP_KEYCODE_6 = 54,
  523. SAPP_KEYCODE_7 = 55,
  524. SAPP_KEYCODE_8 = 56,
  525. SAPP_KEYCODE_9 = 57,
  526. SAPP_KEYCODE_SEMICOLON = 59, /* ; */
  527. SAPP_KEYCODE_EQUAL = 61, /* = */
  528. SAPP_KEYCODE_A = 65,
  529. SAPP_KEYCODE_B = 66,
  530. SAPP_KEYCODE_C = 67,
  531. SAPP_KEYCODE_D = 68,
  532. SAPP_KEYCODE_E = 69,
  533. SAPP_KEYCODE_F = 70,
  534. SAPP_KEYCODE_G = 71,
  535. SAPP_KEYCODE_H = 72,
  536. SAPP_KEYCODE_I = 73,
  537. SAPP_KEYCODE_J = 74,
  538. SAPP_KEYCODE_K = 75,
  539. SAPP_KEYCODE_L = 76,
  540. SAPP_KEYCODE_M = 77,
  541. SAPP_KEYCODE_N = 78,
  542. SAPP_KEYCODE_O = 79,
  543. SAPP_KEYCODE_P = 80,
  544. SAPP_KEYCODE_Q = 81,
  545. SAPP_KEYCODE_R = 82,
  546. SAPP_KEYCODE_S = 83,
  547. SAPP_KEYCODE_T = 84,
  548. SAPP_KEYCODE_U = 85,
  549. SAPP_KEYCODE_V = 86,
  550. SAPP_KEYCODE_W = 87,
  551. SAPP_KEYCODE_X = 88,
  552. SAPP_KEYCODE_Y = 89,
  553. SAPP_KEYCODE_Z = 90,
  554. SAPP_KEYCODE_LEFT_BRACKET = 91, /* [ */
  555. SAPP_KEYCODE_BACKSLASH = 92, /* \ */
  556. SAPP_KEYCODE_RIGHT_BRACKET = 93, /* ] */
  557. SAPP_KEYCODE_GRAVE_ACCENT = 96, /* ` */
  558. SAPP_KEYCODE_WORLD_1 = 161, /* non-US #1 */
  559. SAPP_KEYCODE_WORLD_2 = 162, /* non-US #2 */
  560. SAPP_KEYCODE_ESCAPE = 256,
  561. SAPP_KEYCODE_ENTER = 257,
  562. SAPP_KEYCODE_TAB = 258,
  563. SAPP_KEYCODE_BACKSPACE = 259,
  564. SAPP_KEYCODE_INSERT = 260,
  565. SAPP_KEYCODE_DELETE = 261,
  566. SAPP_KEYCODE_RIGHT = 262,
  567. SAPP_KEYCODE_LEFT = 263,
  568. SAPP_KEYCODE_DOWN = 264,
  569. SAPP_KEYCODE_UP = 265,
  570. SAPP_KEYCODE_PAGE_UP = 266,
  571. SAPP_KEYCODE_PAGE_DOWN = 267,
  572. SAPP_KEYCODE_HOME = 268,
  573. SAPP_KEYCODE_END = 269,
  574. SAPP_KEYCODE_CAPS_LOCK = 280,
  575. SAPP_KEYCODE_SCROLL_LOCK = 281,
  576. SAPP_KEYCODE_NUM_LOCK = 282,
  577. SAPP_KEYCODE_PRINT_SCREEN = 283,
  578. SAPP_KEYCODE_PAUSE = 284,
  579. SAPP_KEYCODE_F1 = 290,
  580. SAPP_KEYCODE_F2 = 291,
  581. SAPP_KEYCODE_F3 = 292,
  582. SAPP_KEYCODE_F4 = 293,
  583. SAPP_KEYCODE_F5 = 294,
  584. SAPP_KEYCODE_F6 = 295,
  585. SAPP_KEYCODE_F7 = 296,
  586. SAPP_KEYCODE_F8 = 297,
  587. SAPP_KEYCODE_F9 = 298,
  588. SAPP_KEYCODE_F10 = 299,
  589. SAPP_KEYCODE_F11 = 300,
  590. SAPP_KEYCODE_F12 = 301,
  591. SAPP_KEYCODE_F13 = 302,
  592. SAPP_KEYCODE_F14 = 303,
  593. SAPP_KEYCODE_F15 = 304,
  594. SAPP_KEYCODE_F16 = 305,
  595. SAPP_KEYCODE_F17 = 306,
  596. SAPP_KEYCODE_F18 = 307,
  597. SAPP_KEYCODE_F19 = 308,
  598. SAPP_KEYCODE_F20 = 309,
  599. SAPP_KEYCODE_F21 = 310,
  600. SAPP_KEYCODE_F22 = 311,
  601. SAPP_KEYCODE_F23 = 312,
  602. SAPP_KEYCODE_F24 = 313,
  603. SAPP_KEYCODE_F25 = 314,
  604. SAPP_KEYCODE_KP_0 = 320,
  605. SAPP_KEYCODE_KP_1 = 321,
  606. SAPP_KEYCODE_KP_2 = 322,
  607. SAPP_KEYCODE_KP_3 = 323,
  608. SAPP_KEYCODE_KP_4 = 324,
  609. SAPP_KEYCODE_KP_5 = 325,
  610. SAPP_KEYCODE_KP_6 = 326,
  611. SAPP_KEYCODE_KP_7 = 327,
  612. SAPP_KEYCODE_KP_8 = 328,
  613. SAPP_KEYCODE_KP_9 = 329,
  614. SAPP_KEYCODE_KP_DECIMAL = 330,
  615. SAPP_KEYCODE_KP_DIVIDE = 331,
  616. SAPP_KEYCODE_KP_MULTIPLY = 332,
  617. SAPP_KEYCODE_KP_SUBTRACT = 333,
  618. SAPP_KEYCODE_KP_ADD = 334,
  619. SAPP_KEYCODE_KP_ENTER = 335,
  620. SAPP_KEYCODE_KP_EQUAL = 336,
  621. SAPP_KEYCODE_LEFT_SHIFT = 340,
  622. SAPP_KEYCODE_LEFT_CONTROL = 341,
  623. SAPP_KEYCODE_LEFT_ALT = 342,
  624. SAPP_KEYCODE_LEFT_SUPER = 343,
  625. SAPP_KEYCODE_RIGHT_SHIFT = 344,
  626. SAPP_KEYCODE_RIGHT_CONTROL = 345,
  627. SAPP_KEYCODE_RIGHT_ALT = 346,
  628. SAPP_KEYCODE_RIGHT_SUPER = 347,
  629. SAPP_KEYCODE_MENU = 348,
  630. } sapp_keycode;
  631. typedef struct sapp_touchpoint {
  632. uintptr_t identifier;
  633. float pos_x;
  634. float pos_y;
  635. bool changed;
  636. } sapp_touchpoint;
  637. typedef enum sapp_mousebutton {
  638. SAPP_MOUSEBUTTON_INVALID = -1,
  639. SAPP_MOUSEBUTTON_LEFT = 0,
  640. SAPP_MOUSEBUTTON_RIGHT = 1,
  641. SAPP_MOUSEBUTTON_MIDDLE = 2,
  642. } sapp_mousebutton;
  643. enum {
  644. SAPP_MODIFIER_SHIFT = (1<<0),
  645. SAPP_MODIFIER_CTRL = (1<<1),
  646. SAPP_MODIFIER_ALT = (1<<2),
  647. SAPP_MODIFIER_SUPER = (1<<3)
  648. };
  649. typedef struct sapp_event {
  650. uint64_t frame_count;
  651. sapp_event_type type;
  652. sapp_keycode key_code;
  653. uint32_t char_code;
  654. bool key_repeat;
  655. uint32_t modifiers;
  656. sapp_mousebutton mouse_button;
  657. float mouse_x;
  658. float mouse_y;
  659. float scroll_x;
  660. float scroll_y;
  661. int num_touches;
  662. sapp_touchpoint touches[SAPP_MAX_TOUCHPOINTS];
  663. int window_width;
  664. int window_height;
  665. int framebuffer_width;
  666. int framebuffer_height;
  667. } sapp_event;
  668. typedef struct sapp_desc {
  669. void (*init_cb)(void); /* these are the user-provided callbacks without user data */
  670. void (*frame_cb)(void);
  671. void (*cleanup_cb)(void);
  672. void (*event_cb)(const sapp_event*);
  673. void (*fail_cb)(const char*);
  674. void* user_data; /* these are the user-provided callbacks with user data */
  675. void (*init_userdata_cb)(void*);
  676. void (*frame_userdata_cb)(void*);
  677. void (*cleanup_userdata_cb)(void*);
  678. void (*event_userdata_cb)(const sapp_event*, void*);
  679. void (*fail_userdata_cb)(const char*, void*);
  680. int width; /* the preferred width of the window / canvas */
  681. int height; /* the preferred height of the window / canvas */
  682. int sample_count; /* MSAA sample count */
  683. int swap_interval; /* the preferred swap interval (ignored on some platforms) */
  684. bool high_dpi; /* whether the rendering canvas is full-resolution on HighDPI displays */
  685. bool fullscreen; /* whether the window should be created in fullscreen mode */
  686. bool alpha; /* whether the framebuffer should have an alpha channel (ignored on some platforms) */
  687. const char* window_title; /* the window title as UTF-8 encoded string */
  688. bool user_cursor; /* if true, user is expected to manage cursor image in SAPP_EVENTTYPE_UPDATE_CURSOR */
  689. bool enable_clipboard; /* enable clipboard access, default is false */
  690. int clipboard_size; /* max size of clipboard content in bytes */
  691. const char* html5_canvas_name; /* the name (id) of the HTML5 canvas element, default is "canvas" */
  692. bool html5_canvas_resize; /* if true, the HTML5 canvas size is set to sapp_desc.width/height, otherwise canvas size is tracked */
  693. bool html5_preserve_drawing_buffer; /* HTML5 only: whether to preserve default framebuffer content between frames */
  694. bool html5_premultiplied_alpha; /* HTML5 only: whether the rendered pixels use premultiplied alpha convention */
  695. bool html5_ask_leave_site; /* initial state of the internal html5_ask_leave_site flag (see sapp_html5_ask_leave_site()) */
  696. bool ios_keyboard_resizes_canvas; /* if true, showing the iOS keyboard shrinks the canvas */
  697. bool gl_force_gles2; /* if true, setup GLES2/WebGL even if GLES3/WebGL2 is available */
  698. } sapp_desc;
  699. /* user-provided functions */
  700. extern sapp_desc sokol_main(int argc, char* argv[]);
  701. /* returns true after sokol-app has been initialized */
  702. SOKOL_API_DECL bool sapp_isvalid(void);
  703. /* returns the current framebuffer width in pixels */
  704. SOKOL_API_DECL int sapp_width(void);
  705. /* returns the current framebuffer height in pixels */
  706. SOKOL_API_DECL int sapp_height(void);
  707. /* returns true when high_dpi was requested and actually running in a high-dpi scenario */
  708. SOKOL_API_DECL bool sapp_high_dpi(void);
  709. /* returns the dpi scaling factor (window pixels to framebuffer pixels) */
  710. SOKOL_API_DECL float sapp_dpi_scale(void);
  711. /* show or hide the mobile device onscreen keyboard */
  712. SOKOL_API_DECL void sapp_show_keyboard(bool visible);
  713. /* return true if the mobile device onscreen keyboard is currently shown */
  714. SOKOL_API_DECL bool sapp_keyboard_shown(void);
  715. /* show or hide the mouse cursor */
  716. SOKOL_API_DECL void sapp_show_mouse(bool visible);
  717. /* show or hide the mouse cursor */
  718. SOKOL_API_DECL bool sapp_mouse_shown();
  719. /* return the userdata pointer optionally provided in sapp_desc */
  720. SOKOL_API_DECL void* sapp_userdata(void);
  721. /* return a copy of the sapp_desc structure */
  722. SOKOL_API_DECL sapp_desc sapp_query_desc(void);
  723. /* initiate a "soft quit" (sends SAPP_EVENTTYPE_QUIT_REQUESTED) */
  724. SOKOL_API_DECL void sapp_request_quit(void);
  725. /* cancel a pending quit (when SAPP_EVENTTYPE_QUIT_REQUESTED has been received) */
  726. SOKOL_API_DECL void sapp_cancel_quit(void);
  727. /* initiate a "hard quit" (quit application without sending SAPP_EVENTTYPE_QUIT_REQUSTED) */
  728. SOKOL_API_DECL void sapp_quit(void);
  729. /* call from inside event callback to consume the current event (don't forward to platform) */
  730. SOKOL_API_DECL void sapp_consume_event(void);
  731. /* get the current frame counter (for comparison with sapp_event.frame_count) */
  732. SOKOL_API_DECL uint64_t sapp_frame_count(void);
  733. /* write string into clipboard */
  734. SOKOL_API_DECL void sapp_set_clipboard_string(const char* str);
  735. /* read string from clipboard (usually during SAPP_EVENTTYPE_CLIPBOARD_PASTED) */
  736. SOKOL_API_DECL const char* sapp_get_clipboard_string(void);
  737. /* special run-function for SOKOL_NO_ENTRY (in standard mode this is an empty stub) */
  738. SOKOL_API_DECL int sapp_run(const sapp_desc* desc);
  739. /* GL: return true when GLES2 fallback is active (to detect fallback from GLES3) */
  740. SOKOL_API_DECL bool sapp_gles2(void);
  741. /* HTML5: enable or disable the hardwired "Leave Site?" dialog box */
  742. SOKOL_API_DECL void sapp_html5_ask_leave_site(bool ask);
  743. /* Metal: get ARC-bridged pointer to Metal device object */
  744. SOKOL_API_DECL const void* sapp_metal_get_device(void);
  745. /* Metal: get ARC-bridged pointer to this frame's renderpass descriptor */
  746. SOKOL_API_DECL const void* sapp_metal_get_renderpass_descriptor(void);
  747. /* Metal: get ARC-bridged pointer to current drawable */
  748. SOKOL_API_DECL const void* sapp_metal_get_drawable(void);
  749. /* macOS: get ARC-bridged pointer to macOS NSWindow */
  750. SOKOL_API_DECL const void* sapp_macos_get_window(void);
  751. /* iOS: get ARC-bridged pointer to iOS UIWindow */
  752. SOKOL_API_DECL const void* sapp_ios_get_window(void);
  753. /* D3D11: get pointer to ID3D11Device object */
  754. SOKOL_API_DECL const void* sapp_d3d11_get_device(void);
  755. /* D3D11: get pointer to ID3D11DeviceContext object */
  756. SOKOL_API_DECL const void* sapp_d3d11_get_device_context(void);
  757. /* D3D11: get pointer to ID3D11RenderTargetView object */
  758. SOKOL_API_DECL const void* sapp_d3d11_get_render_target_view(void);
  759. /* D3D11: get pointer to ID3D11DepthStencilView */
  760. SOKOL_API_DECL const void* sapp_d3d11_get_depth_stencil_view(void);
  761. /* Win32: get the HWND window handle */
  762. SOKOL_API_DECL const void* sapp_win32_get_hwnd(void);
  763. /* Android: get native activity handle */
  764. SOKOL_API_DECL const void* sapp_android_get_native_activity(void);
  765. #ifdef __cplusplus
  766. } /* extern "C" */
  767. #endif
  768. #endif // SOKOL_APP_INCLUDED
  769. /*-- IMPLEMENTATION ----------------------------------------------------------*/
  770. #ifdef SOKOL_IMPL
  771. #define SOKOL_APP_IMPL_INCLUDED (1)
  772. #ifdef _MSC_VER
  773. #pragma warning(push)
  774. #pragma warning(disable:4201) /* nonstandard extension used: nameless struct/union */
  775. #pragma warning(disable:4115) /* named type definition in parentheses */
  776. #pragma warning(disable:4054) /* 'type cast': from function pointer */
  777. #pragma warning(disable:4055) /* 'type cast': from data pointer */
  778. #pragma warning(disable:4505) /* unreferenced local function has been removed */
  779. #pragma warning(disable:4115) /* /W4: 'ID3D11ModuleInstance': named type definition in parentheses (in d3d11.h) */
  780. #endif
  781. #include <string.h> /* memset */
  782. /* check if the config defines are alright */
  783. #if defined(__APPLE__)
  784. #if !__has_feature(objc_arc)
  785. #error "sokol_app.h requires ARC (Automatic Reference Counting) on MacOS and iOS"
  786. #endif
  787. #include <TargetConditionals.h>
  788. #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
  789. /* iOS */
  790. #if !defined(SOKOL_METAL) && !defined(SOKOL_GLES3)
  791. #error("sokol_app.h: unknown 3D API selected for iOS, must be SOKOL_METAL or SOKOL_GLES3")
  792. #endif
  793. #else
  794. /* MacOS */
  795. #if !defined(SOKOL_METAL) && !defined(SOKOL_GLCORE33)
  796. #error("sokol_app.h: unknown 3D API selected for MacOS, must be SOKOL_METAL or SOKOL_GLCORE33")
  797. #endif
  798. #endif
  799. #elif defined(__EMSCRIPTEN__)
  800. /* emscripten (asm.js or wasm) */
  801. #if !defined(SOKOL_GLES3) && !defined(SOKOL_GLES2)
  802. #error("sokol_app.h: unknown 3D API selected for emscripten, must be SOKOL_GLES3 or SOKOL_GLES2")
  803. #endif
  804. #elif defined(_WIN32)
  805. /* Windows (D3D11 or GL) */
  806. #if !defined(SOKOL_D3D11) && !defined(SOKOL_GLCORE33)
  807. #error("sokol_app.h: unknown 3D API selected for Win32, must be SOKOL_D3D11 or SOKOL_GLCORE33")
  808. #endif
  809. #elif defined(__ANDROID__)
  810. /* Android */
  811. #if !defined(SOKOL_GLES3) && !defined(SOKOL_GLES2)
  812. #error("sokol_app.h: unknown 3D API selected for Android, must be SOKOL_GLES3 or SOKOL_GLES2")
  813. #endif
  814. #if defined(SOKOL_NO_ENTRY)
  815. #error("sokol_app.h: SOKOL_NO_ENTRY is not supported on Android")
  816. #endif
  817. #elif defined(__linux__) || defined(__unix__)
  818. /* Linux */
  819. #if !defined(SOKOL_GLCORE33)
  820. #error("sokol_app.h: unknown 3D API selected for Linux, must be SOKOL_GLCORE33")
  821. #endif
  822. #else
  823. #error "sokol_app.h: Unknown platform"
  824. #endif
  825. #ifndef SOKOL_API_IMPL
  826. #define SOKOL_API_IMPL
  827. #endif
  828. #ifndef SOKOL_DEBUG
  829. #ifndef NDEBUG
  830. #define SOKOL_DEBUG (1)
  831. #endif
  832. #endif
  833. #ifndef SOKOL_ASSERT
  834. #include <assert.h>
  835. #define SOKOL_ASSERT(c) assert(c)
  836. #endif
  837. #if !defined(SOKOL_CALLOC) || !defined(SOKOL_FREE)
  838. #include <stdlib.h>
  839. #endif
  840. #if !defined(SOKOL_CALLOC)
  841. #define SOKOL_CALLOC(n,s) calloc(n,s)
  842. #endif
  843. #if !defined(SOKOL_FREE)
  844. #define SOKOL_FREE(p) free(p)
  845. #endif
  846. #ifndef SOKOL_LOG
  847. #ifdef SOKOL_DEBUG
  848. #if defined(__ANDROID__)
  849. #include <android/log.h>
  850. #define SOKOL_LOG(s) { SOKOL_ASSERT(s); __android_log_write(ANDROID_LOG_INFO, "SOKOL_APP", s); }
  851. #else
  852. #include <stdio.h>
  853. #define SOKOL_LOG(s) { SOKOL_ASSERT(s); puts(s); }
  854. #endif
  855. #else
  856. #define SOKOL_LOG(s)
  857. #endif
  858. #endif
  859. #ifndef SOKOL_ABORT
  860. #include <stdlib.h>
  861. #define SOKOL_ABORT() abort()
  862. #endif
  863. #ifndef _SOKOL_PRIVATE
  864. #if defined(__GNUC__)
  865. #define _SOKOL_PRIVATE __attribute__((unused)) static
  866. #else
  867. #define _SOKOL_PRIVATE static
  868. #endif
  869. #endif
  870. #ifndef _SOKOL_UNUSED
  871. #define _SOKOL_UNUSED(x) (void)(x)
  872. #endif
  873. /* helper macros */
  874. #define _sapp_def(val, def) (((val) == 0) ? (def) : (val))
  875. #define _sapp_absf(a) (((a)<0.0f)?-(a):(a))
  876. enum {
  877. _SAPP_MAX_TITLE_LENGTH = 128,
  878. };
  879. typedef struct {
  880. bool valid;
  881. int window_width;
  882. int window_height;
  883. int framebuffer_width;
  884. int framebuffer_height;
  885. int sample_count;
  886. int swap_interval;
  887. float dpi_scale;
  888. bool gles2_fallback;
  889. bool first_frame;
  890. bool init_called;
  891. bool cleanup_called;
  892. bool quit_requested;
  893. bool quit_ordered;
  894. bool event_consumed;
  895. const char* html5_canvas_name;
  896. bool html5_ask_leave_site;
  897. char window_title[_SAPP_MAX_TITLE_LENGTH]; /* UTF-8 */
  898. wchar_t window_title_wide[_SAPP_MAX_TITLE_LENGTH]; /* UTF-32 or UCS-2 */
  899. uint64_t frame_count;
  900. float mouse_x;
  901. float mouse_y;
  902. bool win32_mouse_tracked;
  903. bool onscreen_keyboard_shown;
  904. sapp_event event;
  905. sapp_desc desc;
  906. sapp_keycode keycodes[SAPP_MAX_KEYCODES];
  907. bool clipboard_enabled;
  908. int clipboard_size;
  909. char* clipboard;
  910. } _sapp_state;
  911. static _sapp_state _sapp;
  912. _SOKOL_PRIVATE void _sapp_fail(const char* msg) {
  913. if (_sapp.desc.fail_cb) {
  914. _sapp.desc.fail_cb(msg);
  915. }
  916. else if (_sapp.desc.fail_userdata_cb) {
  917. _sapp.desc.fail_userdata_cb(msg, _sapp.desc.user_data);
  918. }
  919. else {
  920. SOKOL_LOG(msg);
  921. }
  922. SOKOL_ABORT();
  923. }
  924. _SOKOL_PRIVATE void _sapp_call_init(void) {
  925. if (_sapp.desc.init_cb) {
  926. _sapp.desc.init_cb();
  927. }
  928. else if (_sapp.desc.init_userdata_cb) {
  929. _sapp.desc.init_userdata_cb(_sapp.desc.user_data);
  930. }
  931. _sapp.init_called = true;
  932. }
  933. _SOKOL_PRIVATE void _sapp_call_frame(void) {
  934. if (_sapp.init_called && !_sapp.cleanup_called) {
  935. if (_sapp.desc.frame_cb) {
  936. _sapp.desc.frame_cb();
  937. }
  938. else if (_sapp.desc.frame_userdata_cb) {
  939. _sapp.desc.frame_userdata_cb(_sapp.desc.user_data);
  940. }
  941. }
  942. }
  943. _SOKOL_PRIVATE void _sapp_call_cleanup(void) {
  944. if (!_sapp.cleanup_called) {
  945. if (_sapp.desc.cleanup_cb) {
  946. _sapp.desc.cleanup_cb();
  947. }
  948. else if (_sapp.desc.cleanup_userdata_cb) {
  949. _sapp.desc.cleanup_userdata_cb(_sapp.desc.user_data);
  950. }
  951. _sapp.cleanup_called = true;
  952. }
  953. }
  954. _SOKOL_PRIVATE bool _sapp_call_event(const sapp_event* e) {
  955. if (!_sapp.cleanup_called) {
  956. if (_sapp.desc.event_cb) {
  957. _sapp.desc.event_cb(e);
  958. }
  959. else if (_sapp.desc.event_userdata_cb) {
  960. _sapp.desc.event_userdata_cb(e, _sapp.desc.user_data);
  961. }
  962. }
  963. if (_sapp.event_consumed) {
  964. _sapp.event_consumed = false;
  965. return true;
  966. }
  967. else {
  968. return false;
  969. }
  970. }
  971. _SOKOL_PRIVATE void _sapp_strcpy(const char* src, char* dst, int max_len) {
  972. SOKOL_ASSERT(src && dst && (max_len > 0));
  973. char* const end = &(dst[max_len-1]);
  974. char c = 0;
  975. for (int i = 0; i < max_len; i++) {
  976. c = *src;
  977. if (c != 0) {
  978. src++;
  979. }
  980. *dst++ = c;
  981. }
  982. /* truncated? */
  983. if (c != 0) {
  984. *end = 0;
  985. }
  986. }
  987. _SOKOL_PRIVATE void _sapp_init_state(const sapp_desc* desc) {
  988. memset(&_sapp, 0, sizeof(_sapp));
  989. _sapp.desc = *desc;
  990. _sapp.first_frame = true;
  991. _sapp.window_width = _sapp_def(_sapp.desc.width, 640);
  992. _sapp.window_height = _sapp_def(_sapp.desc.height, 480);
  993. _sapp.framebuffer_width = _sapp.window_width;
  994. _sapp.framebuffer_height = _sapp.window_height;
  995. _sapp.sample_count = _sapp_def(_sapp.desc.sample_count, 1);
  996. _sapp.swap_interval = _sapp_def(_sapp.desc.swap_interval, 1);
  997. _sapp.html5_canvas_name = _sapp_def(_sapp.desc.html5_canvas_name, "canvas");
  998. _sapp.html5_ask_leave_site = _sapp.desc.html5_ask_leave_site;
  999. _sapp.clipboard_enabled = _sapp.desc.enable_clipboard;
  1000. if (_sapp.clipboard_enabled) {
  1001. _sapp.clipboard_size = _sapp_def(_sapp.desc.clipboard_size, 8192);
  1002. _sapp.clipboard = (char*) SOKOL_CALLOC(1, _sapp.clipboard_size);
  1003. }
  1004. if (_sapp.desc.window_title) {
  1005. _sapp_strcpy(_sapp.desc.window_title, _sapp.window_title, sizeof(_sapp.window_title));
  1006. }
  1007. else {
  1008. _sapp_strcpy("sokol_app", _sapp.window_title, sizeof(_sapp.window_title));
  1009. }
  1010. _sapp.dpi_scale = 1.0f;
  1011. }
  1012. _SOKOL_PRIVATE void _sapp_discard_state(void) {
  1013. if (_sapp.clipboard_enabled) {
  1014. SOKOL_ASSERT(_sapp.clipboard);
  1015. SOKOL_FREE((void*)_sapp.clipboard);
  1016. }
  1017. memset(&_sapp, 0, sizeof(_sapp));
  1018. }
  1019. _SOKOL_PRIVATE void _sapp_init_event(sapp_event_type type) {
  1020. memset(&_sapp.event, 0, sizeof(_sapp.event));
  1021. _sapp.event.type = type;
  1022. _sapp.event.frame_count = _sapp.frame_count;
  1023. _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID;
  1024. _sapp.event.window_width = _sapp.window_width;
  1025. _sapp.event.window_height = _sapp.window_height;
  1026. _sapp.event.framebuffer_width = _sapp.framebuffer_width;
  1027. _sapp.event.framebuffer_height = _sapp.framebuffer_height;
  1028. }
  1029. _SOKOL_PRIVATE bool _sapp_events_enabled(void) {
  1030. /* only send events when an event callback is set, and the init function was called */
  1031. return (_sapp.desc.event_cb || _sapp.desc.event_userdata_cb) && _sapp.init_called;
  1032. }
  1033. _SOKOL_PRIVATE sapp_keycode _sapp_translate_key(int scan_code) {
  1034. if ((scan_code >= 0) && (scan_code < SAPP_MAX_KEYCODES)) {
  1035. return _sapp.keycodes[scan_code];
  1036. }
  1037. else {
  1038. return SAPP_KEYCODE_INVALID;
  1039. }
  1040. }
  1041. _SOKOL_PRIVATE void _sapp_frame(void) {
  1042. if (_sapp.first_frame) {
  1043. _sapp.first_frame = false;
  1044. _sapp_call_init();
  1045. }
  1046. _sapp_call_frame();
  1047. _sapp.frame_count++;
  1048. }
  1049. /*== MacOS/iOS ===============================================================*/
  1050. #if defined(__APPLE__)
  1051. /*== MacOS ===================================================================*/
  1052. #if defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
  1053. #if defined(SOKOL_METAL)
  1054. #import <Metal/Metal.h>
  1055. #import <MetalKit/MetalKit.h>
  1056. #elif defined(SOKOL_GLCORE33)
  1057. #ifndef GL_SILENCE_DEPRECATION
  1058. #define GL_SILENCE_DEPRECATION
  1059. #endif
  1060. #include <Cocoa/Cocoa.h>
  1061. #include <OpenGL/gl3.h>
  1062. #endif
  1063. @interface _sapp_macos_app_delegate : NSObject<NSApplicationDelegate>
  1064. @end
  1065. @interface _sapp_macos_window_delegate : NSObject<NSWindowDelegate>
  1066. @end
  1067. #if defined(SOKOL_METAL)
  1068. @interface _sapp_macos_mtk_view_dlg : NSObject<MTKViewDelegate>
  1069. @end
  1070. @interface _sapp_macos_view : MTKView
  1071. {
  1072. NSTrackingArea* trackingArea;
  1073. }
  1074. @end
  1075. #elif defined(SOKOL_GLCORE33)
  1076. @interface _sapp_macos_view : NSOpenGLView
  1077. {
  1078. NSTrackingArea* trackingArea;
  1079. }
  1080. - (void)timerFired:(id)sender;
  1081. - (void)prepareOpenGL;
  1082. - (void)drawRect:(NSRect)bounds;
  1083. @end
  1084. #endif
  1085. static NSWindow* _sapp_macos_window_obj;
  1086. static _sapp_macos_window_delegate* _sapp_macos_win_dlg_obj;
  1087. static _sapp_macos_app_delegate* _sapp_macos_app_dlg_obj;
  1088. static _sapp_macos_view* _sapp_view_obj;
  1089. #if defined(SOKOL_METAL)
  1090. static _sapp_macos_mtk_view_dlg* _sapp_macos_mtk_view_dlg_obj;
  1091. static id<MTLDevice> _sapp_mtl_device_obj;
  1092. #elif defined(SOKOL_GLCORE33)
  1093. static NSOpenGLPixelFormat* _sapp_macos_glpixelformat_obj;
  1094. static NSTimer* _sapp_macos_timer_obj;
  1095. #endif
  1096. static uint32_t _sapp_macos_flags_changed_store;
  1097. _SOKOL_PRIVATE void _sapp_macos_init_keytable(void) {
  1098. _sapp.keycodes[0x1D] = SAPP_KEYCODE_0;
  1099. _sapp.keycodes[0x12] = SAPP_KEYCODE_1;
  1100. _sapp.keycodes[0x13] = SAPP_KEYCODE_2;
  1101. _sapp.keycodes[0x14] = SAPP_KEYCODE_3;
  1102. _sapp.keycodes[0x15] = SAPP_KEYCODE_4;
  1103. _sapp.keycodes[0x17] = SAPP_KEYCODE_5;
  1104. _sapp.keycodes[0x16] = SAPP_KEYCODE_6;
  1105. _sapp.keycodes[0x1A] = SAPP_KEYCODE_7;
  1106. _sapp.keycodes[0x1C] = SAPP_KEYCODE_8;
  1107. _sapp.keycodes[0x19] = SAPP_KEYCODE_9;
  1108. _sapp.keycodes[0x00] = SAPP_KEYCODE_A;
  1109. _sapp.keycodes[0x0B] = SAPP_KEYCODE_B;
  1110. _sapp.keycodes[0x08] = SAPP_KEYCODE_C;
  1111. _sapp.keycodes[0x02] = SAPP_KEYCODE_D;
  1112. _sapp.keycodes[0x0E] = SAPP_KEYCODE_E;
  1113. _sapp.keycodes[0x03] = SAPP_KEYCODE_F;
  1114. _sapp.keycodes[0x05] = SAPP_KEYCODE_G;
  1115. _sapp.keycodes[0x04] = SAPP_KEYCODE_H;
  1116. _sapp.keycodes[0x22] = SAPP_KEYCODE_I;
  1117. _sapp.keycodes[0x26] = SAPP_KEYCODE_J;
  1118. _sapp.keycodes[0x28] = SAPP_KEYCODE_K;
  1119. _sapp.keycodes[0x25] = SAPP_KEYCODE_L;
  1120. _sapp.keycodes[0x2E] = SAPP_KEYCODE_M;
  1121. _sapp.keycodes[0x2D] = SAPP_KEYCODE_N;
  1122. _sapp.keycodes[0x1F] = SAPP_KEYCODE_O;
  1123. _sapp.keycodes[0x23] = SAPP_KEYCODE_P;
  1124. _sapp.keycodes[0x0C] = SAPP_KEYCODE_Q;
  1125. _sapp.keycodes[0x0F] = SAPP_KEYCODE_R;
  1126. _sapp.keycodes[0x01] = SAPP_KEYCODE_S;
  1127. _sapp.keycodes[0x11] = SAPP_KEYCODE_T;
  1128. _sapp.keycodes[0x20] = SAPP_KEYCODE_U;
  1129. _sapp.keycodes[0x09] = SAPP_KEYCODE_V;
  1130. _sapp.keycodes[0x0D] = SAPP_KEYCODE_W;
  1131. _sapp.keycodes[0x07] = SAPP_KEYCODE_X;
  1132. _sapp.keycodes[0x10] = SAPP_KEYCODE_Y;
  1133. _sapp.keycodes[0x06] = SAPP_KEYCODE_Z;
  1134. _sapp.keycodes[0x27] = SAPP_KEYCODE_APOSTROPHE;
  1135. _sapp.keycodes[0x2A] = SAPP_KEYCODE_BACKSLASH;
  1136. _sapp.keycodes[0x2B] = SAPP_KEYCODE_COMMA;
  1137. _sapp.keycodes[0x18] = SAPP_KEYCODE_EQUAL;
  1138. _sapp.keycodes[0x32] = SAPP_KEYCODE_GRAVE_ACCENT;
  1139. _sapp.keycodes[0x21] = SAPP_KEYCODE_LEFT_BRACKET;
  1140. _sapp.keycodes[0x1B] = SAPP_KEYCODE_MINUS;
  1141. _sapp.keycodes[0x2F] = SAPP_KEYCODE_PERIOD;
  1142. _sapp.keycodes[0x1E] = SAPP_KEYCODE_RIGHT_BRACKET;
  1143. _sapp.keycodes[0x29] = SAPP_KEYCODE_SEMICOLON;
  1144. _sapp.keycodes[0x2C] = SAPP_KEYCODE_SLASH;
  1145. _sapp.keycodes[0x0A] = SAPP_KEYCODE_WORLD_1;
  1146. _sapp.keycodes[0x33] = SAPP_KEYCODE_BACKSPACE;
  1147. _sapp.keycodes[0x39] = SAPP_KEYCODE_CAPS_LOCK;
  1148. _sapp.keycodes[0x75] = SAPP_KEYCODE_DELETE;
  1149. _sapp.keycodes[0x7D] = SAPP_KEYCODE_DOWN;
  1150. _sapp.keycodes[0x77] = SAPP_KEYCODE_END;
  1151. _sapp.keycodes[0x24] = SAPP_KEYCODE_ENTER;
  1152. _sapp.keycodes[0x35] = SAPP_KEYCODE_ESCAPE;
  1153. _sapp.keycodes[0x7A] = SAPP_KEYCODE_F1;
  1154. _sapp.keycodes[0x78] = SAPP_KEYCODE_F2;
  1155. _sapp.keycodes[0x63] = SAPP_KEYCODE_F3;
  1156. _sapp.keycodes[0x76] = SAPP_KEYCODE_F4;
  1157. _sapp.keycodes[0x60] = SAPP_KEYCODE_F5;
  1158. _sapp.keycodes[0x61] = SAPP_KEYCODE_F6;
  1159. _sapp.keycodes[0x62] = SAPP_KEYCODE_F7;
  1160. _sapp.keycodes[0x64] = SAPP_KEYCODE_F8;
  1161. _sapp.keycodes[0x65] = SAPP_KEYCODE_F9;
  1162. _sapp.keycodes[0x6D] = SAPP_KEYCODE_F10;
  1163. _sapp.keycodes[0x67] = SAPP_KEYCODE_F11;
  1164. _sapp.keycodes[0x6F] = SAPP_KEYCODE_F12;
  1165. _sapp.keycodes[0x69] = SAPP_KEYCODE_F13;
  1166. _sapp.keycodes[0x6B] = SAPP_KEYCODE_F14;
  1167. _sapp.keycodes[0x71] = SAPP_KEYCODE_F15;
  1168. _sapp.keycodes[0x6A] = SAPP_KEYCODE_F16;
  1169. _sapp.keycodes[0x40] = SAPP_KEYCODE_F17;
  1170. _sapp.keycodes[0x4F] = SAPP_KEYCODE_F18;
  1171. _sapp.keycodes[0x50] = SAPP_KEYCODE_F19;
  1172. _sapp.keycodes[0x5A] = SAPP_KEYCODE_F20;
  1173. _sapp.keycodes[0x73] = SAPP_KEYCODE_HOME;
  1174. _sapp.keycodes[0x72] = SAPP_KEYCODE_INSERT;
  1175. _sapp.keycodes[0x7B] = SAPP_KEYCODE_LEFT;
  1176. _sapp.keycodes[0x3A] = SAPP_KEYCODE_LEFT_ALT;
  1177. _sapp.keycodes[0x3B] = SAPP_KEYCODE_LEFT_CONTROL;
  1178. _sapp.keycodes[0x38] = SAPP_KEYCODE_LEFT_SHIFT;
  1179. _sapp.keycodes[0x37] = SAPP_KEYCODE_LEFT_SUPER;
  1180. _sapp.keycodes[0x6E] = SAPP_KEYCODE_MENU;
  1181. _sapp.keycodes[0x47] = SAPP_KEYCODE_NUM_LOCK;
  1182. _sapp.keycodes[0x79] = SAPP_KEYCODE_PAGE_DOWN;
  1183. _sapp.keycodes[0x74] = SAPP_KEYCODE_PAGE_UP;
  1184. _sapp.keycodes[0x7C] = SAPP_KEYCODE_RIGHT;
  1185. _sapp.keycodes[0x3D] = SAPP_KEYCODE_RIGHT_ALT;
  1186. _sapp.keycodes[0x3E] = SAPP_KEYCODE_RIGHT_CONTROL;
  1187. _sapp.keycodes[0x3C] = SAPP_KEYCODE_RIGHT_SHIFT;
  1188. _sapp.keycodes[0x36] = SAPP_KEYCODE_RIGHT_SUPER;
  1189. _sapp.keycodes[0x31] = SAPP_KEYCODE_SPACE;
  1190. _sapp.keycodes[0x30] = SAPP_KEYCODE_TAB;
  1191. _sapp.keycodes[0x7E] = SAPP_KEYCODE_UP;
  1192. _sapp.keycodes[0x52] = SAPP_KEYCODE_KP_0;
  1193. _sapp.keycodes[0x53] = SAPP_KEYCODE_KP_1;
  1194. _sapp.keycodes[0x54] = SAPP_KEYCODE_KP_2;
  1195. _sapp.keycodes[0x55] = SAPP_KEYCODE_KP_3;
  1196. _sapp.keycodes[0x56] = SAPP_KEYCODE_KP_4;
  1197. _sapp.keycodes[0x57] = SAPP_KEYCODE_KP_5;
  1198. _sapp.keycodes[0x58] = SAPP_KEYCODE_KP_6;
  1199. _sapp.keycodes[0x59] = SAPP_KEYCODE_KP_7;
  1200. _sapp.keycodes[0x5B] = SAPP_KEYCODE_KP_8;
  1201. _sapp.keycodes[0x5C] = SAPP_KEYCODE_KP_9;
  1202. _sapp.keycodes[0x45] = SAPP_KEYCODE_KP_ADD;
  1203. _sapp.keycodes[0x41] = SAPP_KEYCODE_KP_DECIMAL;
  1204. _sapp.keycodes[0x4B] = SAPP_KEYCODE_KP_DIVIDE;
  1205. _sapp.keycodes[0x4C] = SAPP_KEYCODE_KP_ENTER;
  1206. _sapp.keycodes[0x51] = SAPP_KEYCODE_KP_EQUAL;
  1207. _sapp.keycodes[0x43] = SAPP_KEYCODE_KP_MULTIPLY;
  1208. _sapp.keycodes[0x4E] = SAPP_KEYCODE_KP_SUBTRACT;
  1209. }
  1210. _SOKOL_PRIVATE void _sapp_run(const sapp_desc* desc) {
  1211. _sapp_init_state(desc);
  1212. _sapp_macos_init_keytable();
  1213. [NSApplication sharedApplication];
  1214. NSApp.activationPolicy = NSApplicationActivationPolicyRegular;
  1215. _sapp_macos_app_dlg_obj = [[_sapp_macos_app_delegate alloc] init];
  1216. NSApp.delegate = _sapp_macos_app_dlg_obj;
  1217. [NSApp activateIgnoringOtherApps:YES];
  1218. [NSApp run];
  1219. _sapp_discard_state();
  1220. }
  1221. /* MacOS entry function */
  1222. #if !defined(SOKOL_NO_ENTRY)
  1223. int main(int argc, char* argv[]) {
  1224. sapp_desc desc = sokol_main(argc, argv);
  1225. _sapp_run(&desc);
  1226. return 0;
  1227. }
  1228. #endif /* SOKOL_NO_ENTRY */
  1229. _SOKOL_PRIVATE void _sapp_macos_update_dimensions(void) {
  1230. #if defined(SOKOL_METAL)
  1231. const CGSize fb_size = [_sapp_view_obj drawableSize];
  1232. _sapp.framebuffer_width = fb_size.width;
  1233. _sapp.framebuffer_height = fb_size.height;
  1234. #elif defined(SOKOL_GLCORE33)
  1235. const NSRect fb_rect = [_sapp_view_obj convertRectToBacking:[_sapp_view_obj frame]];
  1236. _sapp.framebuffer_width = fb_rect.size.width;
  1237. _sapp.framebuffer_height = fb_rect.size.height;
  1238. #endif
  1239. const NSRect bounds = [_sapp_view_obj bounds];
  1240. _sapp.window_width = bounds.size.width;
  1241. _sapp.window_height = bounds.size.height;
  1242. SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0));
  1243. _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float)_sapp.window_width;
  1244. }
  1245. _SOKOL_PRIVATE void _sapp_macos_frame(void) {
  1246. const NSPoint mouse_pos = [_sapp_macos_window_obj mouseLocationOutsideOfEventStream];
  1247. _sapp.mouse_x = mouse_pos.x * _sapp.dpi_scale;
  1248. _sapp.mouse_y = _sapp.framebuffer_height - (mouse_pos.y * _sapp.dpi_scale) - 1;
  1249. _sapp_frame();
  1250. if (_sapp.quit_requested || _sapp.quit_ordered) {
  1251. [_sapp_macos_window_obj performClose:nil];
  1252. }
  1253. }
  1254. @implementation _sapp_macos_app_delegate
  1255. - (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
  1256. if (_sapp.desc.fullscreen) {
  1257. NSRect screen_rect = NSScreen.mainScreen.frame;
  1258. _sapp.window_width = screen_rect.size.width;
  1259. _sapp.window_height = screen_rect.size.height;
  1260. if (_sapp.desc.high_dpi) {
  1261. _sapp.framebuffer_width = 2 * _sapp.window_width;
  1262. _sapp.framebuffer_height = 2 * _sapp.window_height;
  1263. }
  1264. else {
  1265. _sapp.framebuffer_width = _sapp.window_width;
  1266. _sapp.framebuffer_height = _sapp.window_height;
  1267. }
  1268. _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width;
  1269. }
  1270. const NSUInteger style =
  1271. NSWindowStyleMaskTitled |
  1272. NSWindowStyleMaskClosable |
  1273. NSWindowStyleMaskMiniaturizable |
  1274. NSWindowStyleMaskResizable;
  1275. NSRect window_rect = NSMakeRect(0, 0, _sapp.window_width, _sapp.window_height);
  1276. _sapp_macos_window_obj = [[NSWindow alloc]
  1277. initWithContentRect:window_rect
  1278. styleMask:style
  1279. backing:NSBackingStoreBuffered
  1280. defer:NO];
  1281. _sapp_macos_window_obj.title = [NSString stringWithUTF8String:_sapp.window_title];
  1282. _sapp_macos_window_obj.acceptsMouseMovedEvents = YES;
  1283. _sapp_macos_window_obj.restorable = YES;
  1284. _sapp_macos_win_dlg_obj = [[_sapp_macos_window_delegate alloc] init];
  1285. _sapp_macos_window_obj.delegate = _sapp_macos_win_dlg_obj;
  1286. #if defined(SOKOL_METAL)
  1287. _sapp_mtl_device_obj = MTLCreateSystemDefaultDevice();
  1288. _sapp_macos_mtk_view_dlg_obj = [[_sapp_macos_mtk_view_dlg alloc] init];
  1289. _sapp_view_obj = [[_sapp_macos_view alloc] init];
  1290. [_sapp_view_obj updateTrackingAreas];
  1291. _sapp_view_obj.preferredFramesPerSecond = 60 / _sapp.swap_interval;
  1292. _sapp_view_obj.delegate = _sapp_macos_mtk_view_dlg_obj;
  1293. _sapp_view_obj.device = _sapp_mtl_device_obj;
  1294. _sapp_view_obj.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
  1295. _sapp_view_obj.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
  1296. _sapp_view_obj.sampleCount = _sapp.sample_count;
  1297. _sapp_macos_window_obj.contentView = _sapp_view_obj;
  1298. [_sapp_macos_window_obj makeFirstResponder:_sapp_view_obj];
  1299. if (!_sapp.desc.high_dpi) {
  1300. CGSize drawable_size = { (CGFloat) _sapp.framebuffer_width, (CGFloat) _sapp.framebuffer_height };
  1301. _sapp_view_obj.drawableSize = drawable_size;
  1302. }
  1303. _sapp_macos_update_dimensions();
  1304. _sapp_view_obj.layer.magnificationFilter = kCAFilterNearest;
  1305. #elif defined(SOKOL_GLCORE33)
  1306. NSOpenGLPixelFormatAttribute attrs[32];
  1307. int i = 0;
  1308. attrs[i++] = NSOpenGLPFAAccelerated;
  1309. attrs[i++] = NSOpenGLPFADoubleBuffer;
  1310. attrs[i++] = NSOpenGLPFAOpenGLProfile; attrs[i++] = NSOpenGLProfileVersion3_2Core;
  1311. attrs[i++] = NSOpenGLPFAColorSize; attrs[i++] = 24;
  1312. attrs[i++] = NSOpenGLPFAAlphaSize; attrs[i++] = 8;
  1313. attrs[i++] = NSOpenGLPFADepthSize; attrs[i++] = 24;
  1314. attrs[i++] = NSOpenGLPFAStencilSize; attrs[i++] = 8;
  1315. if (_sapp.sample_count > 1) {
  1316. attrs[i++] = NSOpenGLPFAMultisample;
  1317. attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 1;
  1318. attrs[i++] = NSOpenGLPFASamples; attrs[i++] = _sapp.sample_count;
  1319. }
  1320. else {
  1321. attrs[i++] = NSOpenGLPFASampleBuffers; attrs[i++] = 0;
  1322. }
  1323. attrs[i++] = 0;
  1324. _sapp_macos_glpixelformat_obj = [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs];
  1325. SOKOL_ASSERT(_sapp_macos_glpixelformat_obj != nil);
  1326. _sapp_view_obj = [[_sapp_macos_view alloc]
  1327. initWithFrame:window_rect
  1328. pixelFormat:_sapp_macos_glpixelformat_obj];
  1329. [_sapp_view_obj updateTrackingAreas];
  1330. if (_sapp.desc.high_dpi) {
  1331. [_sapp_view_obj setWantsBestResolutionOpenGLSurface:YES];
  1332. }
  1333. else {
  1334. [_sapp_view_obj setWantsBestResolutionOpenGLSurface:NO];
  1335. }
  1336. _sapp_macos_window_obj.contentView = _sapp_view_obj;
  1337. [_sapp_macos_window_obj makeFirstResponder:_sapp_view_obj];
  1338. _sapp_macos_timer_obj = [NSTimer timerWithTimeInterval:0.001
  1339. target:_sapp_view_obj
  1340. selector:@selector(timerFired:)
  1341. userInfo:nil
  1342. repeats:YES];
  1343. [[NSRunLoop currentRunLoop] addTimer:_sapp_macos_timer_obj forMode:NSDefaultRunLoopMode];
  1344. #endif
  1345. _sapp.valid = true;
  1346. if (_sapp.desc.fullscreen) {
  1347. /* on GL, this already toggles a rendered frame, so set the valid flag before */
  1348. [_sapp_macos_window_obj toggleFullScreen:self];
  1349. }
  1350. else {
  1351. [_sapp_macos_window_obj center];
  1352. }
  1353. [_sapp_macos_window_obj makeKeyAndOrderFront:nil];
  1354. }
  1355. - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication*)sender {
  1356. return YES;
  1357. }
  1358. @end
  1359. _SOKOL_PRIVATE uint32_t _sapp_macos_mod(NSEventModifierFlags f) {
  1360. uint32_t m = 0;
  1361. if (f & NSEventModifierFlagShift) {
  1362. m |= SAPP_MODIFIER_SHIFT;
  1363. }
  1364. if (f & NSEventModifierFlagControl) {
  1365. m |= SAPP_MODIFIER_CTRL;
  1366. }
  1367. if (f & NSEventModifierFlagOption) {
  1368. m |= SAPP_MODIFIER_ALT;
  1369. }
  1370. if (f & NSEventModifierFlagCommand) {
  1371. m |= SAPP_MODIFIER_SUPER;
  1372. }
  1373. return m;
  1374. }
  1375. _SOKOL_PRIVATE void _sapp_macos_mouse_event(sapp_event_type type, sapp_mousebutton btn, uint32_t mod) {
  1376. if (_sapp_events_enabled()) {
  1377. _sapp_init_event(type);
  1378. _sapp.event.mouse_button = btn;
  1379. _sapp.event.modifiers = mod;
  1380. _sapp.event.mouse_x = _sapp.mouse_x;
  1381. _sapp.event.mouse_y = _sapp.mouse_y;
  1382. _sapp_call_event(&_sapp.event);
  1383. }
  1384. }
  1385. _SOKOL_PRIVATE void _sapp_macos_key_event(sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mod) {
  1386. if (_sapp_events_enabled()) {
  1387. _sapp_init_event(type);
  1388. _sapp.event.key_code = key;
  1389. _sapp.event.key_repeat = repeat;
  1390. _sapp.event.modifiers = mod;
  1391. _sapp_call_event(&_sapp.event);
  1392. }
  1393. }
  1394. _SOKOL_PRIVATE void _sapp_macos_app_event(sapp_event_type type) {
  1395. if (_sapp_events_enabled()) {
  1396. _sapp_init_event(type);
  1397. _sapp_call_event(&_sapp.event);
  1398. }
  1399. }
  1400. @implementation _sapp_macos_window_delegate
  1401. - (BOOL)windowShouldClose:(id)sender {
  1402. /* only give user-code a chance to intervene when sapp_quit() wasn't already called */
  1403. if (!_sapp.quit_ordered) {
  1404. /* if window should be closed and event handling is enabled, give user code
  1405. a chance to intervene via sapp_cancel_quit()
  1406. */
  1407. _sapp.quit_requested = true;
  1408. _sapp_macos_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED);
  1409. /* user code hasn't intervened, quit the app */
  1410. if (_sapp.quit_requested) {
  1411. _sapp.quit_ordered = true;
  1412. }
  1413. }
  1414. if (_sapp.quit_ordered) {
  1415. _sapp_call_cleanup();
  1416. return YES;
  1417. }
  1418. else {
  1419. return NO;
  1420. }
  1421. }
  1422. - (void)windowDidResize:(NSNotification*)notification {
  1423. _sapp_macos_update_dimensions();
  1424. _sapp_macos_app_event(SAPP_EVENTTYPE_RESIZED);
  1425. }
  1426. - (void)windowDidMiniaturize:(NSNotification*)notification {
  1427. _sapp_macos_app_event(SAPP_EVENTTYPE_ICONIFIED);
  1428. }
  1429. - (void)windowDidDeminiaturize:(NSNotification*)notification {
  1430. _sapp_macos_app_event(SAPP_EVENTTYPE_RESTORED);
  1431. }
  1432. @end
  1433. #if defined(SOKOL_METAL)
  1434. @implementation _sapp_macos_mtk_view_dlg
  1435. - (void)drawInMTKView:(MTKView*)view {
  1436. @autoreleasepool {
  1437. _sapp_macos_frame();
  1438. }
  1439. }
  1440. - (void)mtkView:(MTKView*)view drawableSizeWillChange:(CGSize)size {
  1441. /* this is required by the protocol, but we can't do anything useful here */
  1442. }
  1443. @end
  1444. #endif
  1445. @implementation _sapp_macos_view
  1446. #if defined(SOKOL_GLCORE33)
  1447. - (void)timerFired:(id)sender {
  1448. [self setNeedsDisplay:YES];
  1449. }
  1450. - (void)prepareOpenGL {
  1451. [super prepareOpenGL];
  1452. GLint swapInt = 1;
  1453. NSOpenGLContext* ctx = [_sapp_view_obj openGLContext];
  1454. [ctx setValues:&swapInt forParameter:NSOpenGLContextParameterSwapInterval];
  1455. [ctx makeCurrentContext];
  1456. }
  1457. - (void)drawRect:(NSRect)bound {
  1458. _sapp_macos_frame();
  1459. [[_sapp_view_obj openGLContext] flushBuffer];
  1460. }
  1461. #endif
  1462. - (BOOL)isOpaque {
  1463. return YES;
  1464. }
  1465. - (BOOL)canBecomeKey {
  1466. return YES;
  1467. }
  1468. - (BOOL)acceptsFirstResponder {
  1469. return YES;
  1470. }
  1471. - (void)updateTrackingAreas {
  1472. if (trackingArea != nil) {
  1473. [self removeTrackingArea:trackingArea];
  1474. trackingArea = nil;
  1475. }
  1476. const NSTrackingAreaOptions options = NSTrackingMouseEnteredAndExited |
  1477. NSTrackingActiveInKeyWindow |
  1478. NSTrackingEnabledDuringMouseDrag |
  1479. NSTrackingCursorUpdate |
  1480. NSTrackingInVisibleRect |
  1481. NSTrackingAssumeInside;
  1482. trackingArea = [[NSTrackingArea alloc] initWithRect:[self bounds] options:options owner:self userInfo:nil];
  1483. [self addTrackingArea:trackingArea];
  1484. [super updateTrackingAreas];
  1485. }
  1486. - (void)mouseEntered:(NSEvent*)event {
  1487. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags));
  1488. }
  1489. - (void)mouseExited:(NSEvent*)event {
  1490. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags));
  1491. }
  1492. - (void)mouseDown:(NSEvent*)event {
  1493. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mod(event.modifierFlags));
  1494. }
  1495. - (void)mouseUp:(NSEvent*)event {
  1496. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_LEFT, _sapp_macos_mod(event.modifierFlags));
  1497. }
  1498. - (void)rightMouseDown:(NSEvent*)event {
  1499. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_RIGHT, _sapp_macos_mod(event.modifierFlags));
  1500. }
  1501. - (void)rightMouseUp:(NSEvent*)event {
  1502. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_RIGHT, _sapp_macos_mod(event.modifierFlags));
  1503. }
  1504. - (void)otherMouseDown:(NSEvent*)event {
  1505. if (2 == event.buttonNumber) {
  1506. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_MIDDLE, _sapp_macos_mod(event.modifierFlags));
  1507. }
  1508. }
  1509. - (void)otherMouseUp:(NSEvent*)event {
  1510. if (2 == event.buttonNumber) {
  1511. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_MIDDLE, _sapp_macos_mod(event.modifierFlags));
  1512. }
  1513. }
  1514. - (void)mouseMoved:(NSEvent*)event {
  1515. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags));
  1516. }
  1517. - (void)mouseDragged:(NSEvent*)event {
  1518. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID , _sapp_macos_mod(event.modifierFlags));
  1519. }
  1520. - (void)rightMouseDragged:(NSEvent*)event {
  1521. _sapp_macos_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_macos_mod(event.modifierFlags));
  1522. }
  1523. - (void)scrollWheel:(NSEvent*)event {
  1524. if (_sapp_events_enabled()) {
  1525. float dx = (float) event.scrollingDeltaX;
  1526. float dy = (float) event.scrollingDeltaY;
  1527. if (event.hasPreciseScrollingDeltas) {
  1528. dx *= 0.1;
  1529. dy *= 0.1;
  1530. }
  1531. if ((_sapp_absf(dx) > 0.0f) || (_sapp_absf(dy) > 0.0f)) {
  1532. _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL);
  1533. _sapp.event.modifiers = _sapp_macos_mod(event.modifierFlags);
  1534. _sapp.event.mouse_x = _sapp.mouse_x;
  1535. _sapp.event.mouse_y = _sapp.mouse_y;
  1536. _sapp.event.scroll_x = dx;
  1537. _sapp.event.scroll_y = dy;
  1538. _sapp_call_event(&_sapp.event);
  1539. }
  1540. }
  1541. }
  1542. - (void)keyDown:(NSEvent*)event {
  1543. if (_sapp_events_enabled()) {
  1544. const uint32_t mods = _sapp_macos_mod(event.modifierFlags);
  1545. /* NOTE: macOS doesn't send keyUp events while the Cmd key is pressed,
  1546. as a workaround, to prevent key presses from sticking we'll send
  1547. a keyup event following right after the keydown if SUPER is also pressed
  1548. */
  1549. const sapp_keycode key_code = _sapp_translate_key(event.keyCode);
  1550. _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_DOWN, key_code, event.isARepeat, mods);
  1551. if (0 != (mods & SAPP_MODIFIER_SUPER)) {
  1552. _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_UP, key_code, event.isARepeat, mods);
  1553. }
  1554. const NSString* chars = event.characters;
  1555. const NSUInteger len = chars.length;
  1556. if (len > 0) {
  1557. _sapp_init_event(SAPP_EVENTTYPE_CHAR);
  1558. _sapp.event.modifiers = mods;
  1559. for (NSUInteger i = 0; i < len; i++) {
  1560. const unichar codepoint = [chars characterAtIndex:i];
  1561. if ((codepoint & 0xFF00) == 0xF700) {
  1562. continue;
  1563. }
  1564. _sapp.event.char_code = codepoint;
  1565. _sapp.event.key_repeat = event.isARepeat;
  1566. _sapp_call_event(&_sapp.event);
  1567. }
  1568. }
  1569. /* if this is a Cmd+V (paste), also send a CLIPBOARD_PASTE event */
  1570. if (_sapp.clipboard_enabled && (mods == SAPP_MODIFIER_SUPER) && (key_code == SAPP_KEYCODE_V)) {
  1571. _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED);
  1572. _sapp_call_event(&_sapp.event);
  1573. }
  1574. }
  1575. }
  1576. - (void)keyUp:(NSEvent*)event {
  1577. _sapp_macos_key_event(SAPP_EVENTTYPE_KEY_UP,
  1578. _sapp_translate_key(event.keyCode),
  1579. event.isARepeat,
  1580. _sapp_macos_mod(event.modifierFlags));
  1581. }
  1582. - (void)flagsChanged:(NSEvent*)event {
  1583. const uint32_t old_f = _sapp_macos_flags_changed_store;
  1584. const uint32_t new_f = event.modifierFlags;
  1585. _sapp_macos_flags_changed_store = new_f;
  1586. sapp_keycode key_code = SAPP_KEYCODE_INVALID;
  1587. bool down = false;
  1588. if ((new_f ^ old_f) & NSEventModifierFlagShift) {
  1589. key_code = SAPP_KEYCODE_LEFT_SHIFT;
  1590. down = 0 != (new_f & NSEventModifierFlagShift);
  1591. }
  1592. if ((new_f ^ old_f) & NSEventModifierFlagControl) {
  1593. key_code = SAPP_KEYCODE_LEFT_CONTROL;
  1594. down = 0 != (new_f & NSEventModifierFlagControl);
  1595. }
  1596. if ((new_f ^ old_f) & NSEventModifierFlagOption) {
  1597. key_code = SAPP_KEYCODE_LEFT_ALT;
  1598. down = 0 != (new_f & NSEventModifierFlagOption);
  1599. }
  1600. if ((new_f ^ old_f) & NSEventModifierFlagCommand) {
  1601. key_code = SAPP_KEYCODE_LEFT_SUPER;
  1602. down = 0 != (new_f & NSEventModifierFlagCommand);
  1603. }
  1604. if (key_code != SAPP_KEYCODE_INVALID) {
  1605. _sapp_macos_key_event(down ? SAPP_EVENTTYPE_KEY_DOWN : SAPP_EVENTTYPE_KEY_UP,
  1606. key_code,
  1607. false,
  1608. _sapp_macos_mod(event.modifierFlags));
  1609. }
  1610. }
  1611. - (void)cursorUpdate:(NSEvent*)event {
  1612. if (_sapp.desc.user_cursor) {
  1613. _sapp_macos_app_event(SAPP_EVENTTYPE_UPDATE_CURSOR);
  1614. }
  1615. }
  1616. @end
  1617. void _sapp_macos_set_clipboard_string(const char* str) {
  1618. @autoreleasepool {
  1619. NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
  1620. [pasteboard declareTypes:@[NSPasteboardTypeString] owner:nil];
  1621. [pasteboard setString:@(str) forType:NSPasteboardTypeString];
  1622. }
  1623. }
  1624. const char* _sapp_macos_get_clipboard_string(void) {
  1625. SOKOL_ASSERT(_sapp.clipboard);
  1626. @autoreleasepool {
  1627. _sapp.clipboard[0] = 0;
  1628. NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
  1629. if (![[pasteboard types] containsObject:NSPasteboardTypeString]) {
  1630. return _sapp.clipboard;
  1631. }
  1632. NSString* str = [pasteboard stringForType:NSPasteboardTypeString];
  1633. if (!str) {
  1634. return _sapp.clipboard;
  1635. }
  1636. _sapp_strcpy([str UTF8String], _sapp.clipboard, _sapp.clipboard_size);
  1637. }
  1638. return _sapp.clipboard;
  1639. }
  1640. #endif /* MacOS */
  1641. /*== iOS =====================================================================*/
  1642. #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
  1643. #import <UIKit/UIKit.h>
  1644. #if defined(SOKOL_METAL)
  1645. #import <Metal/Metal.h>
  1646. #import <MetalKit/MetalKit.h>
  1647. #else
  1648. #import <GLKit/GLKit.h>
  1649. #include <OpenGLES/ES3/gl.h>
  1650. #include <OpenGLES/ES3/glext.h>
  1651. #endif
  1652. @interface _sapp_app_delegate : NSObject<UIApplicationDelegate>
  1653. @end
  1654. @interface _sapp_textfield_dlg : NSObject<UITextFieldDelegate>
  1655. - (void)keyboardWasShown:(NSNotification*)notif;
  1656. - (void)keyboardWillBeHidden:(NSNotification*)notif;
  1657. - (void)keyboardDidChangeFrame:(NSNotification*)notif;
  1658. @end
  1659. #if defined(SOKOL_METAL)
  1660. @interface _sapp_ios_mtk_view_dlg : NSObject<MTKViewDelegate>
  1661. @end
  1662. @interface _sapp_ios_view : MTKView;
  1663. @end
  1664. #else
  1665. @interface _sapp_ios_glk_view_dlg : NSObject<GLKViewDelegate>
  1666. @end
  1667. @interface _sapp_ios_view : GLKView
  1668. @end
  1669. #endif
  1670. static bool _sapp_ios_suspended;
  1671. static UIWindow* _sapp_ios_window_obj;
  1672. static _sapp_ios_view* _sapp_view_obj;
  1673. static UITextField* _sapp_ios_textfield_obj;
  1674. static _sapp_textfield_dlg* _sapp_ios_textfield_dlg_obj;
  1675. #if defined(SOKOL_METAL)
  1676. static _sapp_ios_mtk_view_dlg* _sapp_ios_mtk_view_dlg_obj;
  1677. static UIViewController<MTKViewDelegate>* _sapp_ios_view_ctrl_obj;
  1678. static id<MTLDevice> _sapp_mtl_device_obj;
  1679. #else
  1680. static EAGLContext* _sapp_ios_eagl_ctx_obj;
  1681. static _sapp_ios_glk_view_dlg* _sapp_ios_glk_view_dlg_obj;
  1682. static GLKViewController* _sapp_ios_view_ctrl_obj;
  1683. #endif
  1684. _SOKOL_PRIVATE void _sapp_run(const sapp_desc* desc) {
  1685. _sapp_init_state(desc);
  1686. static int argc = 1;
  1687. static char* argv[] = { (char*)"sokol_app" };
  1688. UIApplicationMain(argc, argv, nil, NSStringFromClass([_sapp_app_delegate class]));
  1689. _sapp_discard_state();
  1690. }
  1691. /* iOS entry function */
  1692. #if !defined(SOKOL_NO_ENTRY)
  1693. int main(int argc, char* argv[]) {
  1694. sapp_desc desc = sokol_main(argc, argv);
  1695. _sapp_run(&desc);
  1696. return 0;
  1697. }
  1698. #endif /* SOKOL_NO_ENTRY */
  1699. _SOKOL_PRIVATE void _sapp_ios_app_event(sapp_event_type type) {
  1700. if (_sapp_events_enabled()) {
  1701. _sapp_init_event(type);
  1702. _sapp_call_event(&_sapp.event);
  1703. }
  1704. }
  1705. _SOKOL_PRIVATE void _sapp_ios_update_dimensions(void) {
  1706. CGRect screen_rect = UIScreen.mainScreen.bounds;
  1707. _sapp.window_width = (int) screen_rect.size.width;
  1708. _sapp.window_height = (int) screen_rect.size.height;
  1709. int cur_fb_width, cur_fb_height;
  1710. #if defined(SOKOL_METAL)
  1711. const CGSize fb_size = _sapp_view_obj.drawableSize;
  1712. cur_fb_width = (int) fb_size.width;
  1713. cur_fb_height = (int) fb_size.height;
  1714. #else
  1715. cur_fb_width = (int) _sapp_view_obj.drawableWidth;
  1716. cur_fb_height = (int) _sapp_view_obj.drawableHeight;
  1717. #endif
  1718. const bool dim_changed =
  1719. (_sapp.framebuffer_width != cur_fb_width) ||
  1720. (_sapp.framebuffer_height != cur_fb_height);
  1721. _sapp.framebuffer_width = cur_fb_width;
  1722. _sapp.framebuffer_height = cur_fb_height;
  1723. SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0));
  1724. _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width;
  1725. if (dim_changed) {
  1726. _sapp_ios_app_event(SAPP_EVENTTYPE_RESIZED);
  1727. }
  1728. }
  1729. _SOKOL_PRIVATE void _sapp_ios_frame(void) {
  1730. _sapp_ios_update_dimensions();
  1731. _sapp_frame();
  1732. }
  1733. _SOKOL_PRIVATE void _sapp_ios_show_keyboard(bool shown) {
  1734. /* if not happened yet, create an invisible text field */
  1735. if (nil == _sapp_ios_textfield_obj) {
  1736. _sapp_ios_textfield_dlg_obj = [[_sapp_textfield_dlg alloc] init];
  1737. _sapp_ios_textfield_obj = [[UITextField alloc] initWithFrame:CGRectMake(10, 10, 100, 50)];
  1738. _sapp_ios_textfield_obj.keyboardType = UIKeyboardTypeDefault;
  1739. _sapp_ios_textfield_obj.returnKeyType = UIReturnKeyDefault;
  1740. _sapp_ios_textfield_obj.autocapitalizationType = UITextAutocapitalizationTypeNone;
  1741. _sapp_ios_textfield_obj.autocorrectionType = UITextAutocorrectionTypeNo;
  1742. _sapp_ios_textfield_obj.spellCheckingType = UITextSpellCheckingTypeNo;
  1743. _sapp_ios_textfield_obj.hidden = YES;
  1744. _sapp_ios_textfield_obj.text = @"x";
  1745. _sapp_ios_textfield_obj.delegate = _sapp_ios_textfield_dlg_obj;
  1746. [_sapp_ios_view_ctrl_obj.view addSubview:_sapp_ios_textfield_obj];
  1747. [[NSNotificationCenter defaultCenter] addObserver:_sapp_ios_textfield_dlg_obj
  1748. selector:@selector(keyboardWasShown:)
  1749. name:UIKeyboardDidShowNotification object:nil];
  1750. [[NSNotificationCenter defaultCenter] addObserver:_sapp_ios_textfield_dlg_obj
  1751. selector:@selector(keyboardWillBeHidden:)
  1752. name:UIKeyboardWillHideNotification object:nil];
  1753. [[NSNotificationCenter defaultCenter] addObserver:_sapp_ios_textfield_dlg_obj
  1754. selector:@selector(keyboardDidChangeFrame:)
  1755. name:UIKeyboardDidChangeFrameNotification object:nil];
  1756. }
  1757. if (shown) {
  1758. /* setting the text field as first responder brings up the onscreen keyboard */
  1759. [_sapp_ios_textfield_obj becomeFirstResponder];
  1760. }
  1761. else {
  1762. [_sapp_ios_textfield_obj resignFirstResponder];
  1763. }
  1764. }
  1765. @implementation _sapp_app_delegate
  1766. - (BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
  1767. CGRect screen_rect = UIScreen.mainScreen.bounds;
  1768. _sapp_ios_window_obj = [[UIWindow alloc] initWithFrame:screen_rect];
  1769. _sapp.window_width = screen_rect.size.width;
  1770. _sapp.window_height = screen_rect.size.height;
  1771. if (_sapp.desc.high_dpi) {
  1772. _sapp.framebuffer_width = 2 * _sapp.window_width;
  1773. _sapp.framebuffer_height = 2 * _sapp.window_height;
  1774. }
  1775. else {
  1776. _sapp.framebuffer_width = _sapp.window_width;
  1777. _sapp.framebuffer_height = _sapp.window_height;
  1778. }
  1779. _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float) _sapp.window_width;
  1780. #if defined(SOKOL_METAL)
  1781. _sapp_mtl_device_obj = MTLCreateSystemDefaultDevice();
  1782. _sapp_ios_mtk_view_dlg_obj = [[_sapp_ios_mtk_view_dlg alloc] init];
  1783. _sapp_view_obj = [[_sapp_ios_view alloc] init];
  1784. _sapp_view_obj.preferredFramesPerSecond = 60 / _sapp.swap_interval;
  1785. _sapp_view_obj.delegate = _sapp_ios_mtk_view_dlg_obj;
  1786. _sapp_view_obj.device = _sapp_mtl_device_obj;
  1787. _sapp_view_obj.colorPixelFormat = MTLPixelFormatBGRA8Unorm;
  1788. _sapp_view_obj.depthStencilPixelFormat = MTLPixelFormatDepth32Float_Stencil8;
  1789. _sapp_view_obj.sampleCount = _sapp.sample_count;
  1790. if (_sapp.desc.high_dpi) {
  1791. _sapp_view_obj.contentScaleFactor = 2.0;
  1792. }
  1793. else {
  1794. _sapp_view_obj.contentScaleFactor = 1.0;
  1795. }
  1796. _sapp_view_obj.userInteractionEnabled = YES;
  1797. _sapp_view_obj.multipleTouchEnabled = YES;
  1798. [_sapp_ios_window_obj addSubview:_sapp_view_obj];
  1799. _sapp_ios_view_ctrl_obj = [[UIViewController<MTKViewDelegate> alloc] init];
  1800. _sapp_ios_view_ctrl_obj.view = _sapp_view_obj;
  1801. _sapp_ios_window_obj.rootViewController = _sapp_ios_view_ctrl_obj;
  1802. #else
  1803. if (_sapp.desc.gl_force_gles2) {
  1804. _sapp_ios_eagl_ctx_obj = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
  1805. _sapp.gles2_fallback = true;
  1806. }
  1807. else {
  1808. _sapp_ios_eagl_ctx_obj = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
  1809. if (_sapp_ios_eagl_ctx_obj == nil) {
  1810. _sapp_ios_eagl_ctx_obj = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
  1811. _sapp.gles2_fallback = true;
  1812. }
  1813. }
  1814. _sapp_ios_glk_view_dlg_obj = [[_sapp_ios_glk_view_dlg alloc] init];
  1815. _sapp_view_obj = [[_sapp_ios_view alloc] initWithFrame:screen_rect];
  1816. _sapp_view_obj.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
  1817. _sapp_view_obj.drawableDepthFormat = GLKViewDrawableDepthFormat24;
  1818. _sapp_view_obj.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
  1819. _sapp_view_obj.drawableMultisample = GLKViewDrawableMultisampleNone; /* FIXME */
  1820. _sapp_view_obj.context = _sapp_ios_eagl_ctx_obj;
  1821. _sapp_view_obj.delegate = _sapp_ios_glk_view_dlg_obj;
  1822. _sapp_view_obj.enableSetNeedsDisplay = NO;
  1823. _sapp_view_obj.userInteractionEnabled = YES;
  1824. _sapp_view_obj.multipleTouchEnabled = YES;
  1825. if (_sapp.desc.high_dpi) {
  1826. _sapp_view_obj.contentScaleFactor = 2.0;
  1827. }
  1828. else {
  1829. _sapp_view_obj.contentScaleFactor = 1.0;
  1830. }
  1831. [_sapp_ios_window_obj addSubview:_sapp_view_obj];
  1832. _sapp_ios_view_ctrl_obj = [[GLKViewController alloc] init];
  1833. _sapp_ios_view_ctrl_obj.view = _sapp_view_obj;
  1834. _sapp_ios_view_ctrl_obj.preferredFramesPerSecond = 60 / _sapp.swap_interval;
  1835. _sapp_ios_window_obj.rootViewController = _sapp_ios_view_ctrl_obj;
  1836. #endif
  1837. [_sapp_ios_window_obj makeKeyAndVisible];
  1838. _sapp.valid = true;
  1839. return YES;
  1840. }
  1841. - (void)applicationWillResignActive:(UIApplication *)application {
  1842. if (!_sapp_ios_suspended) {
  1843. _sapp_ios_suspended = true;
  1844. _sapp_ios_app_event(SAPP_EVENTTYPE_SUSPENDED);
  1845. }
  1846. }
  1847. - (void)applicationDidBecomeActive:(UIApplication *)application {
  1848. if (_sapp_ios_suspended) {
  1849. _sapp_ios_suspended = false;
  1850. _sapp_ios_app_event(SAPP_EVENTTYPE_RESUMED);
  1851. }
  1852. }
  1853. @end
  1854. @implementation _sapp_textfield_dlg
  1855. - (void)keyboardWasShown:(NSNotification*)notif {
  1856. _sapp.onscreen_keyboard_shown = true;
  1857. /* query the keyboard's size, and modify the content view's size */
  1858. if (_sapp.desc.ios_keyboard_resizes_canvas) {
  1859. NSDictionary* info = notif.userInfo;
  1860. CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
  1861. CGRect view_frame = UIScreen.mainScreen.bounds;
  1862. view_frame.size.height -= kbd_h;
  1863. _sapp_view_obj.frame = view_frame;
  1864. }
  1865. }
  1866. - (void)keyboardWillBeHidden:(NSNotification*)notif {
  1867. _sapp.onscreen_keyboard_shown = false;
  1868. if (_sapp.desc.ios_keyboard_resizes_canvas) {
  1869. _sapp_view_obj.frame = UIScreen.mainScreen.bounds;
  1870. }
  1871. }
  1872. - (void)keyboardDidChangeFrame:(NSNotification*)notif {
  1873. /* this is for the case when the screen rotation changes while the keyboard is open */
  1874. if (_sapp.onscreen_keyboard_shown && _sapp.desc.ios_keyboard_resizes_canvas) {
  1875. NSDictionary* info = notif.userInfo;
  1876. CGFloat kbd_h = [[info objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue].size.height;
  1877. CGRect view_frame = UIScreen.mainScreen.bounds;
  1878. view_frame.size.height -= kbd_h;
  1879. _sapp_view_obj.frame = view_frame;
  1880. }
  1881. }
  1882. - (BOOL)textField:(UITextField*)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString*)string {
  1883. if (_sapp_events_enabled()) {
  1884. const NSUInteger len = string.length;
  1885. if (len > 0) {
  1886. for (NSUInteger i = 0; i < len; i++) {
  1887. unichar c = [string characterAtIndex:i];
  1888. if (c >= 32) {
  1889. /* ignore surrogates for now */
  1890. if ((c < 0xD800) || (c > 0xDFFF)) {
  1891. _sapp_init_event(SAPP_EVENTTYPE_CHAR);
  1892. _sapp.event.char_code = c;
  1893. _sapp_call_event(&_sapp.event);
  1894. }
  1895. }
  1896. if (c <= 32) {
  1897. sapp_keycode k = SAPP_KEYCODE_INVALID;
  1898. switch (c) {
  1899. case 10: k = SAPP_KEYCODE_ENTER; break;
  1900. case 32: k = SAPP_KEYCODE_SPACE; break;
  1901. default: break;
  1902. }
  1903. if (k != SAPP_KEYCODE_INVALID) {
  1904. _sapp_init_event(SAPP_EVENTTYPE_KEY_DOWN);
  1905. _sapp.event.key_code = k;
  1906. _sapp_call_event(&_sapp.event);
  1907. _sapp_init_event(SAPP_EVENTTYPE_KEY_UP);
  1908. _sapp.event.key_code = k;
  1909. _sapp_call_event(&_sapp.event);
  1910. }
  1911. }
  1912. }
  1913. }
  1914. else {
  1915. /* this was a backspace */
  1916. _sapp_init_event(SAPP_EVENTTYPE_KEY_DOWN);
  1917. _sapp.event.key_code = SAPP_KEYCODE_BACKSPACE;
  1918. _sapp_call_event(&_sapp.event);
  1919. _sapp_init_event(SAPP_EVENTTYPE_KEY_UP);
  1920. _sapp.event.key_code = SAPP_KEYCODE_BACKSPACE;
  1921. _sapp_call_event(&_sapp.event);
  1922. }
  1923. }
  1924. return NO;
  1925. }
  1926. @end
  1927. #if defined(SOKOL_METAL)
  1928. @implementation _sapp_ios_mtk_view_dlg
  1929. - (void)drawInMTKView:(MTKView*)view {
  1930. @autoreleasepool {
  1931. _sapp_ios_frame();
  1932. }
  1933. }
  1934. - (void)mtkView:(MTKView*)view drawableSizeWillChange:(CGSize)size {
  1935. /* this is required by the protocol, but we can't do anything useful here */
  1936. }
  1937. @end
  1938. #else
  1939. @implementation _sapp_ios_glk_view_dlg
  1940. - (void)glkView:(GLKView*)view drawInRect:(CGRect)rect {
  1941. @autoreleasepool {
  1942. _sapp_ios_frame();
  1943. }
  1944. }
  1945. @end
  1946. #endif
  1947. _SOKOL_PRIVATE void _sapp_ios_touch_event(sapp_event_type type, NSSet<UITouch *>* touches, UIEvent* event) {
  1948. if (_sapp_events_enabled()) {
  1949. _sapp_init_event(type);
  1950. NSEnumerator* enumerator = event.allTouches.objectEnumerator;
  1951. UITouch* ios_touch;
  1952. while ((ios_touch = [enumerator nextObject])) {
  1953. if ((_sapp.event.num_touches + 1) < SAPP_MAX_TOUCHPOINTS) {
  1954. CGPoint ios_pos = [ios_touch locationInView:_sapp_view_obj];
  1955. sapp_touchpoint* cur_point = &_sapp.event.touches[_sapp.event.num_touches++];
  1956. cur_point->identifier = (uintptr_t) ios_touch;
  1957. cur_point->pos_x = ios_pos.x * _sapp.dpi_scale;
  1958. cur_point->pos_y = ios_pos.y * _sapp.dpi_scale;
  1959. cur_point->changed = [touches containsObject:ios_touch];
  1960. }
  1961. }
  1962. if (_sapp.event.num_touches > 0) {
  1963. _sapp_call_event(&_sapp.event);
  1964. }
  1965. }
  1966. }
  1967. @implementation _sapp_ios_view
  1968. - (BOOL) isOpaque {
  1969. return YES;
  1970. }
  1971. - (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event {
  1972. _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_BEGAN, touches, event);
  1973. }
  1974. - (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event {
  1975. _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_MOVED, touches, event);
  1976. }
  1977. - (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event {
  1978. _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_ENDED, touches, event);
  1979. }
  1980. - (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent*)event {
  1981. _sapp_ios_touch_event(SAPP_EVENTTYPE_TOUCHES_CANCELLED, touches, event);
  1982. }
  1983. @end
  1984. #endif /* TARGET_OS_IPHONE */
  1985. #endif /* __APPLE__ */
  1986. /*== EMSCRIPTEN ==============================================================*/
  1987. #if defined(__EMSCRIPTEN__)
  1988. #if defined(SOKOL_GLES3)
  1989. #include <GLES3/gl3.h>
  1990. #else
  1991. #ifndef GL_EXT_PROTOTYPES
  1992. #define GL_GLEXT_PROTOTYPES
  1993. #endif
  1994. #include <GLES2/gl2.h>
  1995. #include <GLES2/gl2ext.h>
  1996. #endif
  1997. #include <emscripten/emscripten.h>
  1998. #include <emscripten/html5.h>
  1999. static bool _sapp_emsc_input_created;
  2000. static bool _sapp_emsc_wants_show_keyboard;
  2001. static bool _sapp_emsc_wants_hide_keyboard;
  2002. /* this function is called from a JS event handler when the user hides
  2003. the onscreen keyboard pressing the 'dismiss keyboard key'
  2004. */
  2005. #ifdef __cplusplus
  2006. extern "C" {
  2007. #endif
  2008. EMSCRIPTEN_KEEPALIVE void _sapp_emsc_notify_keyboard_hidden(void) {
  2009. _sapp.onscreen_keyboard_shown = false;
  2010. }
  2011. #ifdef __cplusplus
  2012. } /* extern "C" */
  2013. #endif
  2014. /* Javascript helper functions for mobile virtual keyboard input */
  2015. EM_JS(void, sapp_js_create_textfield, (void), {
  2016. var _sapp_inp = document.createElement("input");
  2017. _sapp_inp.type = "text";
  2018. _sapp_inp.id = "_sokol_app_input_element";
  2019. _sapp_inp.autocapitalize = "none";
  2020. _sapp_inp.addEventListener("focusout", function(_sapp_event) {
  2021. __sapp_emsc_notify_keyboard_hidden()
  2022. });
  2023. document.body.append(_sapp_inp);
  2024. });
  2025. EM_JS(void, sapp_js_focus_textfield, (void), {
  2026. document.getElementById("_sokol_app_input_element").focus();
  2027. });
  2028. EM_JS(void, sapp_js_unfocus_textfield, (void), {
  2029. document.getElementById("_sokol_app_input_element").blur();
  2030. });
  2031. EMSCRIPTEN_KEEPALIVE void _sapp_emsc_onpaste(const char* str) {
  2032. if (_sapp.clipboard_enabled) {
  2033. _sapp_strcpy(str, _sapp.clipboard, _sapp.clipboard_size);
  2034. if (_sapp_events_enabled()) {
  2035. _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED);
  2036. _sapp_call_event(&_sapp.event);
  2037. }
  2038. }
  2039. }
  2040. /* https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onbeforeunload */
  2041. EMSCRIPTEN_KEEPALIVE int _sapp_html5_get_ask_leave_site(void) {
  2042. return _sapp.html5_ask_leave_site ? 1 : 0;
  2043. }
  2044. EM_JS(void, sapp_js_hook_beforeunload, (void), {
  2045. window.addEventListener('beforeunload', function(_sapp_event) {
  2046. if (__sapp_html5_get_ask_leave_site() != 0) {
  2047. _sapp_event.preventDefault();
  2048. _sapp_event.returnValue = ' ';
  2049. }
  2050. });
  2051. });
  2052. EM_JS(void, sapp_js_init_clipboard, (void), {
  2053. window.addEventListener('paste', function(event) {
  2054. var pasted_str = event.clipboardData.getData('text');
  2055. ccall('_sapp_emsc_onpaste', 'void', ['string'], [pasted_str]);
  2056. });
  2057. });
  2058. EM_JS(void, sapp_js_write_clipboard, (const char* c_str), {
  2059. var str = UTF8ToString(c_str);
  2060. var ta = document.createElement('textarea');
  2061. ta.setAttribute('autocomplete', 'off');
  2062. ta.setAttribute('autocorrect', 'off');
  2063. ta.setAttribute('autocapitalize', 'off');
  2064. ta.setAttribute('spellcheck', 'false');
  2065. ta.style.left = -100 + 'px';
  2066. ta.style.top = -100 + 'px';
  2067. ta.style.height = 1;
  2068. ta.style.width = 1;
  2069. ta.value = str;
  2070. document.body.appendChild(ta);
  2071. ta.select();
  2072. document.execCommand('copy');
  2073. document.body.removeChild(ta);
  2074. });
  2075. _SOKOL_PRIVATE void _sapp_emsc_set_clipboard_string(const char* str) {
  2076. sapp_js_write_clipboard(str);
  2077. }
  2078. /* called from the emscripten event handler to update the keyboard visibility
  2079. state, this must happen from an JS input event handler, otherwise
  2080. the request will be ignored by the browser
  2081. */
  2082. _SOKOL_PRIVATE void _sapp_emsc_update_keyboard_state(void) {
  2083. if (_sapp_emsc_wants_show_keyboard) {
  2084. /* create input text field on demand */
  2085. if (!_sapp_emsc_input_created) {
  2086. _sapp_emsc_input_created = true;
  2087. sapp_js_create_textfield();
  2088. }
  2089. /* focus the text input field, this will bring up the keyboard */
  2090. _sapp.onscreen_keyboard_shown = true;
  2091. _sapp_emsc_wants_show_keyboard = false;
  2092. sapp_js_focus_textfield();
  2093. }
  2094. if (_sapp_emsc_wants_hide_keyboard) {
  2095. /* unfocus the text input field */
  2096. if (_sapp_emsc_input_created) {
  2097. _sapp.onscreen_keyboard_shown = false;
  2098. _sapp_emsc_wants_hide_keyboard = false;
  2099. sapp_js_unfocus_textfield();
  2100. }
  2101. }
  2102. }
  2103. /* actually showing the onscreen keyboard must be initiated from a JS
  2104. input event handler, so we'll just keep track of the desired
  2105. state, and the actual state change will happen with the next input event
  2106. */
  2107. _SOKOL_PRIVATE void _sapp_emsc_show_keyboard(bool show) {
  2108. if (show) {
  2109. _sapp_emsc_wants_show_keyboard = true;
  2110. }
  2111. else {
  2112. _sapp_emsc_wants_hide_keyboard = true;
  2113. }
  2114. }
  2115. _SOKOL_PRIVATE EM_BOOL _sapp_emsc_size_changed(int event_type, const EmscriptenUiEvent* ui_event, void* user_data) {
  2116. double w, h;
  2117. emscripten_get_element_css_size(_sapp.html5_canvas_name, &w, &h);
  2118. /* The above method might report zero when toggling HTML5 fullscreen,
  2119. in that case use the window's inner width reported by the
  2120. emscripten event. This works ok when toggling *into* fullscreen
  2121. but doesn't properly restore the previous canvas size when switching
  2122. back from fullscreen.
  2123. In general, due to the HTML5's fullscreen API's flaky nature it is
  2124. recommended to use 'soft fullscreen' (stretching the WebGL canvas
  2125. over the browser windows client rect) with a CSS definition like this:
  2126. position: absolute;
  2127. top: 0px;
  2128. left: 0px;
  2129. margin: 0px;
  2130. border: 0;
  2131. width: 100%;
  2132. height: 100%;
  2133. overflow: hidden;
  2134. display: block;
  2135. */
  2136. if (w < 1.0) {
  2137. w = ui_event->windowInnerWidth;
  2138. }
  2139. else {
  2140. _sapp.window_width = (int) w;
  2141. }
  2142. if (h < 1.0) {
  2143. h = ui_event->windowInnerHeight;
  2144. }
  2145. else {
  2146. _sapp.window_height = (int) h;
  2147. }
  2148. if (_sapp.desc.high_dpi) {
  2149. _sapp.dpi_scale = emscripten_get_device_pixel_ratio();
  2150. }
  2151. _sapp.framebuffer_width = (int) (w * _sapp.dpi_scale);
  2152. _sapp.framebuffer_height = (int) (h * _sapp.dpi_scale);
  2153. SOKOL_ASSERT((_sapp.framebuffer_width > 0) && (_sapp.framebuffer_height > 0));
  2154. emscripten_set_canvas_element_size(_sapp.html5_canvas_name, _sapp.framebuffer_width, _sapp.framebuffer_height);
  2155. if (_sapp_events_enabled()) {
  2156. _sapp_init_event(SAPP_EVENTTYPE_RESIZED);
  2157. _sapp_call_event(&_sapp.event);
  2158. }
  2159. return true;
  2160. }
  2161. _SOKOL_PRIVATE EM_BOOL _sapp_emsc_frame(double time, void* userData) {
  2162. _SOKOL_UNUSED(time);
  2163. _SOKOL_UNUSED(userData);
  2164. _sapp_frame();
  2165. return EM_TRUE;
  2166. }
  2167. _SOKOL_PRIVATE EM_BOOL _sapp_emsc_context_cb(int emsc_type, const void* reserved, void* user_data) {
  2168. sapp_event_type type;
  2169. switch (emsc_type) {
  2170. case EMSCRIPTEN_EVENT_WEBGLCONTEXTLOST: type = SAPP_EVENTTYPE_SUSPENDED; break;
  2171. case EMSCRIPTEN_EVENT_WEBGLCONTEXTRESTORED: type = SAPP_EVENTTYPE_RESUMED; break;
  2172. default: type = SAPP_EVENTTYPE_INVALID; break;
  2173. }
  2174. if (_sapp_events_enabled() && (SAPP_EVENTTYPE_INVALID != type)) {
  2175. _sapp_init_event(type);
  2176. _sapp_call_event(&_sapp.event);
  2177. }
  2178. return true;
  2179. }
  2180. _SOKOL_PRIVATE EM_BOOL _sapp_emsc_mouse_cb(int emsc_type, const EmscriptenMouseEvent* emsc_event, void* user_data) {
  2181. _sapp.mouse_x = (emsc_event->targetX * _sapp.dpi_scale);
  2182. _sapp.mouse_y = (emsc_event->targetY * _sapp.dpi_scale);
  2183. if (_sapp_events_enabled() && (emsc_event->button >= 0) && (emsc_event->button < SAPP_MAX_MOUSEBUTTONS)) {
  2184. sapp_event_type type;
  2185. bool is_button_event = false;
  2186. switch (emsc_type) {
  2187. case EMSCRIPTEN_EVENT_MOUSEDOWN:
  2188. type = SAPP_EVENTTYPE_MOUSE_DOWN;
  2189. is_button_event = true;
  2190. break;
  2191. case EMSCRIPTEN_EVENT_MOUSEUP:
  2192. type = SAPP_EVENTTYPE_MOUSE_UP;
  2193. is_button_event = true;
  2194. break;
  2195. case EMSCRIPTEN_EVENT_MOUSEMOVE:
  2196. type = SAPP_EVENTTYPE_MOUSE_MOVE;
  2197. break;
  2198. case EMSCRIPTEN_EVENT_MOUSEENTER:
  2199. type = SAPP_EVENTTYPE_MOUSE_ENTER;
  2200. break;
  2201. case EMSCRIPTEN_EVENT_MOUSELEAVE:
  2202. type = SAPP_EVENTTYPE_MOUSE_LEAVE;
  2203. break;
  2204. default:
  2205. type = SAPP_EVENTTYPE_INVALID;
  2206. break;
  2207. }
  2208. if (type != SAPP_EVENTTYPE_INVALID) {
  2209. _sapp_init_event(type);
  2210. if (emsc_event->ctrlKey) {
  2211. _sapp.event.modifiers |= SAPP_MODIFIER_CTRL;
  2212. }
  2213. if (emsc_event->shiftKey) {
  2214. _sapp.event.modifiers |= SAPP_MODIFIER_SHIFT;
  2215. }
  2216. if (emsc_event->altKey) {
  2217. _sapp.event.modifiers |= SAPP_MODIFIER_ALT;
  2218. }
  2219. if (emsc_event->metaKey) {
  2220. _sapp.event.modifiers |= SAPP_MODIFIER_SUPER;
  2221. }
  2222. if (is_button_event) {
  2223. switch (emsc_event->button) {
  2224. case 0: _sapp.event.mouse_button = SAPP_MOUSEBUTTON_LEFT; break;
  2225. case 1: _sapp.event.mouse_button = SAPP_MOUSEBUTTON_MIDDLE; break;
  2226. case 2: _sapp.event.mouse_button = SAPP_MOUSEBUTTON_RIGHT; break;
  2227. default: _sapp.event.mouse_button = (sapp_mousebutton)emsc_event->button; break;
  2228. }
  2229. }
  2230. else {
  2231. _sapp.event.mouse_button = SAPP_MOUSEBUTTON_INVALID;
  2232. }
  2233. _sapp.event.mouse_x = _sapp.mouse_x;
  2234. _sapp.event.mouse_y = _sapp.mouse_y;
  2235. _sapp_call_event(&_sapp.event);
  2236. }
  2237. }
  2238. _sapp_emsc_update_keyboard_state();
  2239. return true;
  2240. }
  2241. _SOKOL_PRIVATE EM_BOOL _sapp_emsc_wheel_cb(int emsc_type, const EmscriptenWheelEvent* emsc_event, void* user_data) {
  2242. if (_sapp_events_enabled()) {
  2243. _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL);
  2244. if (emsc_event->mouse.ctrlKey) {
  2245. _sapp.event.modifiers |= SAPP_MODIFIER_CTRL;
  2246. }
  2247. if (emsc_event->mouse.shiftKey) {
  2248. _sapp.event.modifiers |= SAPP_MODIFIER_SHIFT;
  2249. }
  2250. if (emsc_event->mouse.altKey) {
  2251. _sapp.event.modifiers |= SAPP_MODIFIER_ALT;
  2252. }
  2253. if (emsc_event->mouse.metaKey) {
  2254. _sapp.event.modifiers |= SAPP_MODIFIER_SUPER;
  2255. }
  2256. _sapp.event.scroll_x = -0.1 * (float)emsc_event->deltaX;
  2257. _sapp.event.scroll_y = -0.1 * (float)emsc_event->deltaY;
  2258. _sapp_call_event(&_sapp.event);
  2259. }
  2260. _sapp_emsc_update_keyboard_state();
  2261. return true;
  2262. }
  2263. _SOKOL_PRIVATE EM_BOOL _sapp_emsc_key_cb(int emsc_type, const EmscriptenKeyboardEvent* emsc_event, void* user_data) {
  2264. bool retval = true;
  2265. if (_sapp_events_enabled()) {
  2266. sapp_event_type type;
  2267. switch (emsc_type) {
  2268. case EMSCRIPTEN_EVENT_KEYDOWN:
  2269. type = SAPP_EVENTTYPE_KEY_DOWN;
  2270. break;
  2271. case EMSCRIPTEN_EVENT_KEYUP:
  2272. type = SAPP_EVENTTYPE_KEY_UP;
  2273. break;
  2274. case EMSCRIPTEN_EVENT_KEYPRESS:
  2275. type = SAPP_EVENTTYPE_CHAR;
  2276. break;
  2277. default:
  2278. type = SAPP_EVENTTYPE_INVALID;
  2279. break;
  2280. }
  2281. if (type != SAPP_EVENTTYPE_INVALID) {
  2282. bool send_keyup_followup = false;
  2283. _sapp_init_event(type);
  2284. _sapp.event.key_repeat = emsc_event->repeat;
  2285. if (emsc_event->ctrlKey) {
  2286. _sapp.event.modifiers |= SAPP_MODIFIER_CTRL;
  2287. }
  2288. if (emsc_event->shiftKey) {
  2289. _sapp.event.modifiers |= SAPP_MODIFIER_SHIFT;
  2290. }
  2291. if (emsc_event->altKey) {
  2292. _sapp.event.modifiers |= SAPP_MODIFIER_ALT;
  2293. }
  2294. if (emsc_event->metaKey) {
  2295. _sapp.event.modifiers |= SAPP_MODIFIER_SUPER;
  2296. }
  2297. if (type == SAPP_EVENTTYPE_CHAR) {
  2298. _sapp.event.char_code = emsc_event->charCode;
  2299. /* workaround to make Cmd+V work on Safari */
  2300. if ((emsc_event->metaKey) && (emsc_event->charCode == 118)) {
  2301. retval = false;
  2302. }
  2303. }
  2304. else {
  2305. _sapp.event.key_code = _sapp_translate_key(emsc_event->keyCode);
  2306. /* Special hack for macOS: if the Super key is pressed, macOS doesn't
  2307. send keyUp events. As a workaround, to prevent keys from
  2308. "sticking", we'll send a keyup event following a keydown
  2309. when the SUPER key is pressed
  2310. */
  2311. if ((type == SAPP_EVENTTYPE_KEY_DOWN) &&
  2312. (_sapp.event.key_code != SAPP_KEYCODE_LEFT_SUPER) &&
  2313. (_sapp.event.key_code != SAPP_KEYCODE_RIGHT_SUPER) &&
  2314. (_sapp.event.modifiers & SAPP_MODIFIER_SUPER))
  2315. {
  2316. send_keyup_followup = true;
  2317. }
  2318. /* only forward a certain key ranges to the browser */
  2319. switch (_sapp.event.key_code) {
  2320. case SAPP_KEYCODE_WORLD_1:
  2321. case SAPP_KEYCODE_WORLD_2:
  2322. case SAPP_KEYCODE_ESCAPE:
  2323. case SAPP_KEYCODE_ENTER:
  2324. case SAPP_KEYCODE_TAB:
  2325. case SAPP_KEYCODE_BACKSPACE:
  2326. case SAPP_KEYCODE_INSERT:
  2327. case SAPP_KEYCODE_DELETE:
  2328. case SAPP_KEYCODE_RIGHT:
  2329. case SAPP_KEYCODE_LEFT:
  2330. case SAPP_KEYCODE_DOWN:
  2331. case SAPP_KEYCODE_UP:
  2332. case SAPP_KEYCODE_PAGE_UP:
  2333. case SAPP_KEYCODE_PAGE_DOWN:
  2334. case SAPP_KEYCODE_HOME:
  2335. case SAPP_KEYCODE_END:
  2336. case SAPP_KEYCODE_CAPS_LOCK:
  2337. case SAPP_KEYCODE_SCROLL_LOCK:
  2338. case SAPP_KEYCODE_NUM_LOCK:
  2339. case SAPP_KEYCODE_PRINT_SCREEN:
  2340. case SAPP_KEYCODE_PAUSE:
  2341. case SAPP_KEYCODE_F1:
  2342. case SAPP_KEYCODE_F2:
  2343. case SAPP_KEYCODE_F3:
  2344. case SAPP_KEYCODE_F4:
  2345. case SAPP_KEYCODE_F5:
  2346. case SAPP_KEYCODE_F6:
  2347. case SAPP_KEYCODE_F7:
  2348. case SAPP_KEYCODE_F8:
  2349. case SAPP_KEYCODE_F9:
  2350. case SAPP_KEYCODE_F10:
  2351. case SAPP_KEYCODE_F11:
  2352. case SAPP_KEYCODE_F12:
  2353. case SAPP_KEYCODE_F13:
  2354. case SAPP_KEYCODE_F14:
  2355. case SAPP_KEYCODE_F15:
  2356. case SAPP_KEYCODE_F16:
  2357. case SAPP_KEYCODE_F17:
  2358. case SAPP_KEYCODE_F18:
  2359. case SAPP_KEYCODE_F19:
  2360. case SAPP_KEYCODE_F20:
  2361. case SAPP_KEYCODE_F21:
  2362. case SAPP_KEYCODE_F22:
  2363. case SAPP_KEYCODE_F23:
  2364. case SAPP_KEYCODE_F24:
  2365. case SAPP_KEYCODE_F25:
  2366. case SAPP_KEYCODE_LEFT_SHIFT:
  2367. case SAPP_KEYCODE_LEFT_CONTROL:
  2368. case SAPP_KEYCODE_LEFT_ALT:
  2369. case SAPP_KEYCODE_LEFT_SUPER:
  2370. case SAPP_KEYCODE_RIGHT_SHIFT:
  2371. case SAPP_KEYCODE_RIGHT_CONTROL:
  2372. case SAPP_KEYCODE_RIGHT_ALT:
  2373. case SAPP_KEYCODE_RIGHT_SUPER:
  2374. case SAPP_KEYCODE_MENU:
  2375. /* consume the event */
  2376. break;
  2377. default:
  2378. /* forward key to browser */
  2379. retval = false;
  2380. break;
  2381. }
  2382. }
  2383. if (_sapp_call_event(&_sapp.event)) {
  2384. /* consume event via sapp_consume_event() */
  2385. retval = true;
  2386. }
  2387. if (send_keyup_followup) {
  2388. _sapp.event.type = SAPP_EVENTTYPE_KEY_UP;
  2389. if (_sapp_call_event(&_sapp.event)) {
  2390. retval = true;
  2391. }
  2392. }
  2393. }
  2394. }
  2395. _sapp_emsc_update_keyboard_state();
  2396. return retval;
  2397. }
  2398. _SOKOL_PRIVATE EM_BOOL _sapp_emsc_touch_cb(int emsc_type, const EmscriptenTouchEvent* emsc_event, void* user_data) {
  2399. bool retval = true;
  2400. if (_sapp_events_enabled()) {
  2401. sapp_event_type type;
  2402. switch (emsc_type) {
  2403. case EMSCRIPTEN_EVENT_TOUCHSTART:
  2404. type = SAPP_EVENTTYPE_TOUCHES_BEGAN;
  2405. break;
  2406. case EMSCRIPTEN_EVENT_TOUCHMOVE:
  2407. type = SAPP_EVENTTYPE_TOUCHES_MOVED;
  2408. break;
  2409. case EMSCRIPTEN_EVENT_TOUCHEND:
  2410. type = SAPP_EVENTTYPE_TOUCHES_ENDED;
  2411. break;
  2412. case EMSCRIPTEN_EVENT_TOUCHCANCEL:
  2413. type = SAPP_EVENTTYPE_TOUCHES_CANCELLED;
  2414. break;
  2415. default:
  2416. type = SAPP_EVENTTYPE_INVALID;
  2417. retval = false;
  2418. break;
  2419. }
  2420. if (type != SAPP_EVENTTYPE_INVALID) {
  2421. _sapp_init_event(type);
  2422. if (emsc_event->ctrlKey) {
  2423. _sapp.event.modifiers |= SAPP_MODIFIER_CTRL;
  2424. }
  2425. if (emsc_event->shiftKey) {
  2426. _sapp.event.modifiers |= SAPP_MODIFIER_SHIFT;
  2427. }
  2428. if (emsc_event->altKey) {
  2429. _sapp.event.modifiers |= SAPP_MODIFIER_ALT;
  2430. }
  2431. if (emsc_event->metaKey) {
  2432. _sapp.event.modifiers |= SAPP_MODIFIER_SUPER;
  2433. }
  2434. _sapp.event.num_touches = emsc_event->numTouches;
  2435. if (_sapp.event.num_touches > SAPP_MAX_TOUCHPOINTS) {
  2436. _sapp.event.num_touches = SAPP_MAX_TOUCHPOINTS;
  2437. }
  2438. for (int i = 0; i < _sapp.event.num_touches; i++) {
  2439. const EmscriptenTouchPoint* src = &emsc_event->touches[i];
  2440. sapp_touchpoint* dst = &_sapp.event.touches[i];
  2441. dst->identifier = src->identifier;
  2442. dst->pos_x = src->targetX * _sapp.dpi_scale;
  2443. dst->pos_y = src->targetY * _sapp.dpi_scale;
  2444. dst->changed = src->isChanged;
  2445. }
  2446. _sapp_call_event(&_sapp.event);
  2447. }
  2448. }
  2449. _sapp_emsc_update_keyboard_state();
  2450. return retval;
  2451. }
  2452. _SOKOL_PRIVATE void _sapp_emsc_init_keytable(void) {
  2453. _sapp.keycodes[8] = SAPP_KEYCODE_BACKSPACE;
  2454. _sapp.keycodes[9] = SAPP_KEYCODE_TAB;
  2455. _sapp.keycodes[13] = SAPP_KEYCODE_ENTER;
  2456. _sapp.keycodes[16] = SAPP_KEYCODE_LEFT_SHIFT;
  2457. _sapp.keycodes[17] = SAPP_KEYCODE_LEFT_CONTROL;
  2458. _sapp.keycodes[18] = SAPP_KEYCODE_LEFT_ALT;
  2459. _sapp.keycodes[19] = SAPP_KEYCODE_PAUSE;
  2460. _sapp.keycodes[27] = SAPP_KEYCODE_ESCAPE;
  2461. _sapp.keycodes[32] = SAPP_KEYCODE_SPACE;
  2462. _sapp.keycodes[33] = SAPP_KEYCODE_PAGE_UP;
  2463. _sapp.keycodes[34] = SAPP_KEYCODE_PAGE_DOWN;
  2464. _sapp.keycodes[35] = SAPP_KEYCODE_END;
  2465. _sapp.keycodes[36] = SAPP_KEYCODE_HOME;
  2466. _sapp.keycodes[37] = SAPP_KEYCODE_LEFT;
  2467. _sapp.keycodes[38] = SAPP_KEYCODE_UP;
  2468. _sapp.keycodes[39] = SAPP_KEYCODE_RIGHT;
  2469. _sapp.keycodes[40] = SAPP_KEYCODE_DOWN;
  2470. _sapp.keycodes[45] = SAPP_KEYCODE_INSERT;
  2471. _sapp.keycodes[46] = SAPP_KEYCODE_DELETE;
  2472. _sapp.keycodes[48] = SAPP_KEYCODE_0;
  2473. _sapp.keycodes[49] = SAPP_KEYCODE_1;
  2474. _sapp.keycodes[50] = SAPP_KEYCODE_2;
  2475. _sapp.keycodes[51] = SAPP_KEYCODE_3;
  2476. _sapp.keycodes[52] = SAPP_KEYCODE_4;
  2477. _sapp.keycodes[53] = SAPP_KEYCODE_5;
  2478. _sapp.keycodes[54] = SAPP_KEYCODE_6;
  2479. _sapp.keycodes[55] = SAPP_KEYCODE_7;
  2480. _sapp.keycodes[56] = SAPP_KEYCODE_8;
  2481. _sapp.keycodes[57] = SAPP_KEYCODE_9;
  2482. _sapp.keycodes[59] = SAPP_KEYCODE_SEMICOLON;
  2483. _sapp.keycodes[64] = SAPP_KEYCODE_EQUAL;
  2484. _sapp.keycodes[65] = SAPP_KEYCODE_A;
  2485. _sapp.keycodes[66] = SAPP_KEYCODE_B;
  2486. _sapp.keycodes[67] = SAPP_KEYCODE_C;
  2487. _sapp.keycodes[68] = SAPP_KEYCODE_D;
  2488. _sapp.keycodes[69] = SAPP_KEYCODE_E;
  2489. _sapp.keycodes[70] = SAPP_KEYCODE_F;
  2490. _sapp.keycodes[71] = SAPP_KEYCODE_G;
  2491. _sapp.keycodes[72] = SAPP_KEYCODE_H;
  2492. _sapp.keycodes[73] = SAPP_KEYCODE_I;
  2493. _sapp.keycodes[74] = SAPP_KEYCODE_J;
  2494. _sapp.keycodes[75] = SAPP_KEYCODE_K;
  2495. _sapp.keycodes[76] = SAPP_KEYCODE_L;
  2496. _sapp.keycodes[77] = SAPP_KEYCODE_M;
  2497. _sapp.keycodes[78] = SAPP_KEYCODE_N;
  2498. _sapp.keycodes[79] = SAPP_KEYCODE_O;
  2499. _sapp.keycodes[80] = SAPP_KEYCODE_P;
  2500. _sapp.keycodes[81] = SAPP_KEYCODE_Q;
  2501. _sapp.keycodes[82] = SAPP_KEYCODE_R;
  2502. _sapp.keycodes[83] = SAPP_KEYCODE_S;
  2503. _sapp.keycodes[84] = SAPP_KEYCODE_T;
  2504. _sapp.keycodes[85] = SAPP_KEYCODE_U;
  2505. _sapp.keycodes[86] = SAPP_KEYCODE_V;
  2506. _sapp.keycodes[87] = SAPP_KEYCODE_W;
  2507. _sapp.keycodes[88] = SAPP_KEYCODE_X;
  2508. _sapp.keycodes[89] = SAPP_KEYCODE_Y;
  2509. _sapp.keycodes[90] = SAPP_KEYCODE_Z;
  2510. _sapp.keycodes[91] = SAPP_KEYCODE_LEFT_SUPER;
  2511. _sapp.keycodes[93] = SAPP_KEYCODE_MENU;
  2512. _sapp.keycodes[96] = SAPP_KEYCODE_KP_0;
  2513. _sapp.keycodes[97] = SAPP_KEYCODE_KP_1;
  2514. _sapp.keycodes[98] = SAPP_KEYCODE_KP_2;
  2515. _sapp.keycodes[99] = SAPP_KEYCODE_KP_3;
  2516. _sapp.keycodes[100] = SAPP_KEYCODE_KP_4;
  2517. _sapp.keycodes[101] = SAPP_KEYCODE_KP_5;
  2518. _sapp.keycodes[102] = SAPP_KEYCODE_KP_6;
  2519. _sapp.keycodes[103] = SAPP_KEYCODE_KP_7;
  2520. _sapp.keycodes[104] = SAPP_KEYCODE_KP_8;
  2521. _sapp.keycodes[105] = SAPP_KEYCODE_KP_9;
  2522. _sapp.keycodes[106] = SAPP_KEYCODE_KP_MULTIPLY;
  2523. _sapp.keycodes[107] = SAPP_KEYCODE_KP_ADD;
  2524. _sapp.keycodes[109] = SAPP_KEYCODE_KP_SUBTRACT;
  2525. _sapp.keycodes[110] = SAPP_KEYCODE_KP_DECIMAL;
  2526. _sapp.keycodes[111] = SAPP_KEYCODE_KP_DIVIDE;
  2527. _sapp.keycodes[112] = SAPP_KEYCODE_F1;
  2528. _sapp.keycodes[113] = SAPP_KEYCODE_F2;
  2529. _sapp.keycodes[114] = SAPP_KEYCODE_F3;
  2530. _sapp.keycodes[115] = SAPP_KEYCODE_F4;
  2531. _sapp.keycodes[116] = SAPP_KEYCODE_F5;
  2532. _sapp.keycodes[117] = SAPP_KEYCODE_F6;
  2533. _sapp.keycodes[118] = SAPP_KEYCODE_F7;
  2534. _sapp.keycodes[119] = SAPP_KEYCODE_F8;
  2535. _sapp.keycodes[120] = SAPP_KEYCODE_F9;
  2536. _sapp.keycodes[121] = SAPP_KEYCODE_F10;
  2537. _sapp.keycodes[122] = SAPP_KEYCODE_F11;
  2538. _sapp.keycodes[123] = SAPP_KEYCODE_F12;
  2539. _sapp.keycodes[144] = SAPP_KEYCODE_NUM_LOCK;
  2540. _sapp.keycodes[145] = SAPP_KEYCODE_SCROLL_LOCK;
  2541. _sapp.keycodes[173] = SAPP_KEYCODE_MINUS;
  2542. _sapp.keycodes[186] = SAPP_KEYCODE_SEMICOLON;
  2543. _sapp.keycodes[187] = SAPP_KEYCODE_EQUAL;
  2544. _sapp.keycodes[188] = SAPP_KEYCODE_COMMA;
  2545. _sapp.keycodes[189] = SAPP_KEYCODE_MINUS;
  2546. _sapp.keycodes[190] = SAPP_KEYCODE_PERIOD;
  2547. _sapp.keycodes[191] = SAPP_KEYCODE_SLASH;
  2548. _sapp.keycodes[192] = SAPP_KEYCODE_GRAVE_ACCENT;
  2549. _sapp.keycodes[219] = SAPP_KEYCODE_LEFT_BRACKET;
  2550. _sapp.keycodes[220] = SAPP_KEYCODE_BACKSLASH;
  2551. _sapp.keycodes[221] = SAPP_KEYCODE_RIGHT_BRACKET;
  2552. _sapp.keycodes[222] = SAPP_KEYCODE_APOSTROPHE;
  2553. _sapp.keycodes[224] = SAPP_KEYCODE_LEFT_SUPER;
  2554. }
  2555. _SOKOL_PRIVATE void _sapp_emsc_init_clipboard(void) {
  2556. sapp_js_init_clipboard();
  2557. }
  2558. _SOKOL_PRIVATE void _sapp_run(const sapp_desc* desc) {
  2559. _sapp_init_state(desc);
  2560. _sapp_emsc_init_keytable();
  2561. if (_sapp.clipboard_enabled) {
  2562. _sapp_emsc_init_clipboard();
  2563. }
  2564. double w, h;
  2565. if (_sapp.desc.html5_canvas_resize) {
  2566. w = (double) _sapp.desc.width;
  2567. h = (double) _sapp.desc.height;
  2568. }
  2569. else {
  2570. emscripten_get_element_css_size(_sapp.html5_canvas_name, &w, &h);
  2571. emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, false, _sapp_emsc_size_changed);
  2572. }
  2573. if (_sapp.desc.high_dpi) {
  2574. _sapp.dpi_scale = emscripten_get_device_pixel_ratio();
  2575. }
  2576. _sapp.window_width = (int) w;
  2577. _sapp.window_height = (int) h;
  2578. _sapp.framebuffer_width = (int) (w * _sapp.dpi_scale);
  2579. _sapp.framebuffer_height = (int) (h * _sapp.dpi_scale);
  2580. emscripten_set_canvas_element_size(_sapp.html5_canvas_name, _sapp.framebuffer_width, _sapp.framebuffer_height);
  2581. EmscriptenWebGLContextAttributes attrs;
  2582. emscripten_webgl_init_context_attributes(&attrs);
  2583. attrs.alpha = _sapp.desc.alpha;
  2584. attrs.depth = true;
  2585. attrs.stencil = true;
  2586. attrs.antialias = _sapp.sample_count > 1;
  2587. attrs.premultipliedAlpha = _sapp.desc.html5_premultiplied_alpha;
  2588. attrs.preserveDrawingBuffer = _sapp.desc.html5_preserve_drawing_buffer;
  2589. attrs.enableExtensionsByDefault = true;
  2590. #if defined(SOKOL_GLES3)
  2591. if (_sapp.desc.gl_force_gles2) {
  2592. attrs.majorVersion = 1;
  2593. _sapp.gles2_fallback = true;
  2594. }
  2595. else {
  2596. attrs.majorVersion = 2;
  2597. }
  2598. #endif
  2599. EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx = emscripten_webgl_create_context(_sapp.html5_canvas_name, &attrs);
  2600. if (!ctx) {
  2601. attrs.majorVersion = 1;
  2602. ctx = emscripten_webgl_create_context(_sapp.html5_canvas_name, &attrs);
  2603. _sapp.gles2_fallback = true;
  2604. }
  2605. emscripten_webgl_make_context_current(ctx);
  2606. /* some WebGL extension are not enabled automatically by emscripten */
  2607. emscripten_webgl_enable_extension(ctx, "WEBKIT_WEBGL_compressed_texture_pvrtc");
  2608. _sapp.valid = true;
  2609. emscripten_set_mousedown_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
  2610. emscripten_set_mouseup_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
  2611. emscripten_set_mousemove_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
  2612. emscripten_set_mouseenter_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
  2613. emscripten_set_mouseleave_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_mouse_cb);
  2614. emscripten_set_wheel_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_wheel_cb);
  2615. emscripten_set_keydown_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_key_cb);
  2616. emscripten_set_keyup_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_key_cb);
  2617. emscripten_set_keypress_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, true, _sapp_emsc_key_cb);
  2618. emscripten_set_touchstart_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb);
  2619. emscripten_set_touchmove_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb);
  2620. emscripten_set_touchend_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb);
  2621. emscripten_set_touchcancel_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_touch_cb);
  2622. emscripten_set_webglcontextlost_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_context_cb);
  2623. emscripten_set_webglcontextrestored_callback(_sapp.html5_canvas_name, 0, true, _sapp_emsc_context_cb);
  2624. emscripten_request_animation_frame_loop(_sapp_emsc_frame, 0);
  2625. sapp_js_hook_beforeunload();
  2626. // NOT A BUG: do not call _sapp_discard_state()
  2627. }
  2628. #if !defined(SOKOL_NO_ENTRY)
  2629. int main(int argc, char* argv[]) {
  2630. sapp_desc desc = sokol_main(argc, argv);
  2631. _sapp_run(&desc);
  2632. return 0;
  2633. }
  2634. #endif /* SOKOL_NO_ENTRY */
  2635. #endif /* __EMSCRIPTEN__ */
  2636. /*== MISC GL SUPPORT FUNCTIONS ================================================*/
  2637. #if defined(SOKOL_GLCORE33)
  2638. typedef struct {
  2639. int red_bits;
  2640. int green_bits;
  2641. int blue_bits;
  2642. int alpha_bits;
  2643. int depth_bits;
  2644. int stencil_bits;
  2645. int samples;
  2646. bool doublebuffer;
  2647. uintptr_t handle;
  2648. } _sapp_gl_fbconfig;
  2649. _SOKOL_PRIVATE void _sapp_gl_init_fbconfig(_sapp_gl_fbconfig* fbconfig) {
  2650. memset(fbconfig, 0, sizeof(_sapp_gl_fbconfig));
  2651. /* -1 means "don't care" */
  2652. fbconfig->red_bits = -1;
  2653. fbconfig->green_bits = -1;
  2654. fbconfig->blue_bits = -1;
  2655. fbconfig->alpha_bits = -1;
  2656. fbconfig->depth_bits = -1;
  2657. fbconfig->stencil_bits = -1;
  2658. fbconfig->samples = -1;
  2659. }
  2660. _SOKOL_PRIVATE const _sapp_gl_fbconfig* _sapp_gl_choose_fbconfig(const _sapp_gl_fbconfig* desired, const _sapp_gl_fbconfig* alternatives, unsigned int count) {
  2661. unsigned int i;
  2662. unsigned int missing, least_missing = 1000000;
  2663. unsigned int color_diff, least_color_diff = 10000000;
  2664. unsigned int extra_diff, least_extra_diff = 10000000;
  2665. const _sapp_gl_fbconfig* current;
  2666. const _sapp_gl_fbconfig* closest = NULL;
  2667. for (i = 0; i < count; i++) {
  2668. current = alternatives + i;
  2669. if (desired->doublebuffer != current->doublebuffer) {
  2670. continue;
  2671. }
  2672. missing = 0;
  2673. if (desired->alpha_bits > 0 && current->alpha_bits == 0) {
  2674. missing++;
  2675. }
  2676. if (desired->depth_bits > 0 && current->depth_bits == 0) {
  2677. missing++;
  2678. }
  2679. if (desired->stencil_bits > 0 && current->stencil_bits == 0) {
  2680. missing++;
  2681. }
  2682. if (desired->samples > 0 && current->samples == 0) {
  2683. /* Technically, several multisampling buffers could be
  2684. involved, but that's a lower level implementation detail and
  2685. not important to us here, so we count them as one
  2686. */
  2687. missing++;
  2688. }
  2689. /* These polynomials make many small channel size differences matter
  2690. less than one large channel size difference
  2691. Calculate color channel size difference value
  2692. */
  2693. color_diff = 0;
  2694. if (desired->red_bits != -1) {
  2695. color_diff += (desired->red_bits - current->red_bits) * (desired->red_bits - current->red_bits);
  2696. }
  2697. if (desired->green_bits != -1) {
  2698. color_diff += (desired->green_bits - current->green_bits) * (desired->green_bits - current->green_bits);
  2699. }
  2700. if (desired->blue_bits != -1) {
  2701. color_diff += (desired->blue_bits - current->blue_bits) * (desired->blue_bits - current->blue_bits);
  2702. }
  2703. /* Calculate non-color channel size difference value */
  2704. extra_diff = 0;
  2705. if (desired->alpha_bits != -1) {
  2706. extra_diff += (desired->alpha_bits - current->alpha_bits) * (desired->alpha_bits - current->alpha_bits);
  2707. }
  2708. if (desired->depth_bits != -1) {
  2709. extra_diff += (desired->depth_bits - current->depth_bits) * (desired->depth_bits - current->depth_bits);
  2710. }
  2711. if (desired->stencil_bits != -1) {
  2712. extra_diff += (desired->stencil_bits - current->stencil_bits) * (desired->stencil_bits - current->stencil_bits);
  2713. }
  2714. if (desired->samples != -1) {
  2715. extra_diff += (desired->samples - current->samples) * (desired->samples - current->samples);
  2716. }
  2717. /* Figure out if the current one is better than the best one found so far
  2718. Least number of missing buffers is the most important heuristic,
  2719. then color buffer size match and lastly size match for other buffers
  2720. */
  2721. if (missing < least_missing) {
  2722. closest = current;
  2723. }
  2724. else if (missing == least_missing) {
  2725. if ((color_diff < least_color_diff) ||
  2726. (color_diff == least_color_diff && extra_diff < least_extra_diff))
  2727. {
  2728. closest = current;
  2729. }
  2730. }
  2731. if (current == closest) {
  2732. least_missing = missing;
  2733. least_color_diff = color_diff;
  2734. least_extra_diff = extra_diff;
  2735. }
  2736. }
  2737. return closest;
  2738. }
  2739. #endif
  2740. /*== WINDOWS ==================================================================*/
  2741. #if defined(_WIN32)
  2742. #ifndef WIN32_LEAN_AND_MEAN
  2743. #define WIN32_LEAN_AND_MEAN
  2744. #endif
  2745. #include <windows.h>
  2746. #include <windowsx.h>
  2747. #include <shellapi.h>
  2748. #pragma comment (lib, "Shell32.lib")
  2749. #if defined(SOKOL_D3D11)
  2750. #ifndef D3D11_NO_HELPERS
  2751. #define D3D11_NO_HELPERS
  2752. #endif
  2753. #ifndef CINTERFACE
  2754. #define CINTERFACE
  2755. #endif
  2756. #ifndef COBJMACROS
  2757. #define COBJMACROS
  2758. #endif
  2759. #include <windows.h>
  2760. #include <d3d11.h>
  2761. #include <dxgi.h>
  2762. #if (defined(WINAPI_FAMILY_PARTITION) && !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP))
  2763. #pragma comment (lib, "WindowsApp.lib")
  2764. #else
  2765. #pragma comment (lib, "user32.lib")
  2766. #pragma comment (lib, "dxgi.lib")
  2767. #pragma comment (lib, "d3d11.lib")
  2768. #pragma comment (lib, "dxguid.lib")
  2769. #endif
  2770. #endif
  2771. /* see https://github.com/floooh/sokol/issues/138 */
  2772. #ifndef WM_MOUSEHWHEEL
  2773. #define WM_MOUSEHWHEEL (0x020E)
  2774. #endif
  2775. #ifndef DPI_ENUMS_DECLARED
  2776. typedef enum PROCESS_DPI_AWARENESS
  2777. {
  2778. PROCESS_DPI_UNAWARE = 0,
  2779. PROCESS_SYSTEM_DPI_AWARE = 1,
  2780. PROCESS_PER_MONITOR_DPI_AWARE = 2
  2781. } PROCESS_DPI_AWARENESS;
  2782. typedef enum MONITOR_DPI_TYPE {
  2783. MDT_EFFECTIVE_DPI = 0,
  2784. MDT_ANGULAR_DPI = 1,
  2785. MDT_RAW_DPI = 2,
  2786. MDT_DEFAULT = MDT_EFFECTIVE_DPI
  2787. } MONITOR_DPI_TYPE;
  2788. #endif /*DPI_ENUMS_DECLARED*/
  2789. static HWND _sapp_win32_hwnd;
  2790. static HDC _sapp_win32_dc;
  2791. static bool _sapp_win32_in_create_window;
  2792. static bool _sapp_win32_dpi_aware;
  2793. static float _sapp_win32_content_scale;
  2794. static float _sapp_win32_window_scale;
  2795. static float _sapp_win32_mouse_scale;
  2796. static bool _sapp_win32_iconified;
  2797. typedef BOOL(WINAPI * SETPROCESSDPIAWARE_T)(void);
  2798. typedef HRESULT(WINAPI * SETPROCESSDPIAWARENESS_T)(PROCESS_DPI_AWARENESS);
  2799. typedef HRESULT(WINAPI * GETDPIFORMONITOR_T)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*);
  2800. static SETPROCESSDPIAWARE_T _sapp_win32_setprocessdpiaware;
  2801. static SETPROCESSDPIAWARENESS_T _sapp_win32_setprocessdpiawareness;
  2802. static GETDPIFORMONITOR_T _sapp_win32_getdpiformonitor;
  2803. #if defined(SOKOL_D3D11)
  2804. static ID3D11Device* _sapp_d3d11_device;
  2805. static ID3D11DeviceContext* _sapp_d3d11_device_context;
  2806. static DXGI_SWAP_CHAIN_DESC _sapp_dxgi_swap_chain_desc;
  2807. static IDXGISwapChain* _sapp_dxgi_swap_chain;
  2808. static ID3D11Texture2D* _sapp_d3d11_rt;
  2809. static ID3D11RenderTargetView* _sapp_d3d11_rtv;
  2810. static ID3D11Texture2D* _sapp_d3d11_ds;
  2811. static ID3D11DepthStencilView* _sapp_d3d11_dsv;
  2812. #endif
  2813. #define WGL_NUMBER_PIXEL_FORMATS_ARB 0x2000
  2814. #define WGL_SUPPORT_OPENGL_ARB 0x2010
  2815. #define WGL_DRAW_TO_WINDOW_ARB 0x2001
  2816. #define WGL_PIXEL_TYPE_ARB 0x2013
  2817. #define WGL_TYPE_RGBA_ARB 0x202b
  2818. #define WGL_ACCELERATION_ARB 0x2003
  2819. #define WGL_NO_ACCELERATION_ARB 0x2025
  2820. #define WGL_RED_BITS_ARB 0x2015
  2821. #define WGL_RED_SHIFT_ARB 0x2016
  2822. #define WGL_GREEN_BITS_ARB 0x2017
  2823. #define WGL_GREEN_SHIFT_ARB 0x2018
  2824. #define WGL_BLUE_BITS_ARB 0x2019
  2825. #define WGL_BLUE_SHIFT_ARB 0x201a
  2826. #define WGL_ALPHA_BITS_ARB 0x201b
  2827. #define WGL_ALPHA_SHIFT_ARB 0x201c
  2828. #define WGL_ACCUM_BITS_ARB 0x201d
  2829. #define WGL_ACCUM_RED_BITS_ARB 0x201e
  2830. #define WGL_ACCUM_GREEN_BITS_ARB 0x201f
  2831. #define WGL_ACCUM_BLUE_BITS_ARB 0x2020
  2832. #define WGL_ACCUM_ALPHA_BITS_ARB 0x2021
  2833. #define WGL_DEPTH_BITS_ARB 0x2022
  2834. #define WGL_STENCIL_BITS_ARB 0x2023
  2835. #define WGL_AUX_BUFFERS_ARB 0x2024
  2836. #define WGL_STEREO_ARB 0x2012
  2837. #define WGL_DOUBLE_BUFFER_ARB 0x2011
  2838. #define WGL_SAMPLES_ARB 0x2042
  2839. #define WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20a9
  2840. #define WGL_CONTEXT_DEBUG_BIT_ARB 0x00000001
  2841. #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
  2842. #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
  2843. #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
  2844. #define WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
  2845. #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
  2846. #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
  2847. #define WGL_CONTEXT_FLAGS_ARB 0x2094
  2848. #define WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
  2849. #define WGL_LOSE_CONTEXT_ON_RESET_ARB 0x8252
  2850. #define WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
  2851. #define WGL_NO_RESET_NOTIFICATION_ARB 0x8261
  2852. #define WGL_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
  2853. #define WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
  2854. #define WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
  2855. #define WGL_COLORSPACE_EXT 0x309d
  2856. #define WGL_COLORSPACE_SRGB_EXT 0x3089
  2857. #define ERROR_INVALID_VERSION_ARB 0x2095
  2858. #define ERROR_INVALID_PROFILE_ARB 0x2096
  2859. #define ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB 0x2054
  2860. typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int);
  2861. typedef BOOL (WINAPI * PFNWGLGETPIXELFORMATATTRIBIVARBPROC)(HDC,int,int,UINT,const int*,int*);
  2862. typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGEXTPROC)(void);
  2863. typedef const char* (WINAPI * PFNWGLGETEXTENSIONSSTRINGARBPROC)(HDC);
  2864. typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC,HGLRC,const int*);
  2865. typedef HGLRC (WINAPI * PFN_wglCreateContext)(HDC);
  2866. typedef BOOL (WINAPI * PFN_wglDeleteContext)(HGLRC);
  2867. typedef PROC (WINAPI * PFN_wglGetProcAddress)(LPCSTR);
  2868. typedef HDC (WINAPI * PFN_wglGetCurrentDC)(void);
  2869. typedef BOOL (WINAPI * PFN_wglMakeCurrent)(HDC,HGLRC);
  2870. static HINSTANCE _sapp_opengl32;
  2871. static HGLRC _sapp_gl_ctx;
  2872. static PFN_wglCreateContext _sapp_wglCreateContext;
  2873. static PFN_wglDeleteContext _sapp_wglDeleteContext;
  2874. static PFN_wglGetProcAddress _sapp_wglGetProcAddress;
  2875. static PFN_wglGetCurrentDC _sapp_wglGetCurrentDC;
  2876. static PFN_wglMakeCurrent _sapp_wglMakeCurrent;
  2877. static PFNWGLSWAPINTERVALEXTPROC _sapp_SwapIntervalEXT;
  2878. static PFNWGLGETPIXELFORMATATTRIBIVARBPROC _sapp_GetPixelFormatAttribivARB;
  2879. static PFNWGLGETEXTENSIONSSTRINGEXTPROC _sapp_GetExtensionsStringEXT;
  2880. static PFNWGLGETEXTENSIONSSTRINGARBPROC _sapp_GetExtensionsStringARB;
  2881. static PFNWGLCREATECONTEXTATTRIBSARBPROC _sapp_CreateContextAttribsARB;
  2882. static bool _sapp_ext_swap_control;
  2883. static bool _sapp_arb_multisample;
  2884. static bool _sapp_arb_pixel_format;
  2885. static bool _sapp_arb_create_context;
  2886. static bool _sapp_arb_create_context_profile;
  2887. static HWND _sapp_win32_msg_hwnd;
  2888. static HDC _sapp_win32_msg_dc;
  2889. /* NOTE: the optional GL loader only contains the GL constants and functions required for sokol_gfx.h, if you need
  2890. more, you'll need to use you own gl header-generator/loader
  2891. */
  2892. #if !defined(SOKOL_WIN32_NO_GL_LOADER)
  2893. #if defined(SOKOL_GLCORE33)
  2894. #define __gl_h_ 1
  2895. #define __gl32_h_ 1
  2896. #define __gl31_h_ 1
  2897. #define __GL_H__ 1
  2898. #define __glext_h_ 1
  2899. #define __GLEXT_H_ 1
  2900. #define __gltypes_h_ 1
  2901. #define __glcorearb_h_ 1
  2902. #define __gl_glcorearb_h_ 1
  2903. #define GL_APIENTRY APIENTRY
  2904. typedef unsigned int GLenum;
  2905. typedef unsigned int GLuint;
  2906. typedef int GLsizei;
  2907. typedef char GLchar;
  2908. typedef ptrdiff_t GLintptr;
  2909. typedef ptrdiff_t GLsizeiptr;
  2910. typedef double GLclampd;
  2911. typedef unsigned short GLushort;
  2912. typedef unsigned char GLubyte;
  2913. typedef unsigned char GLboolean;
  2914. typedef uint64_t GLuint64;
  2915. typedef double GLdouble;
  2916. typedef unsigned short GLhalf;
  2917. typedef float GLclampf;
  2918. typedef unsigned int GLbitfield;
  2919. typedef signed char GLbyte;
  2920. typedef short GLshort;
  2921. typedef void GLvoid;
  2922. typedef int64_t GLint64;
  2923. typedef float GLfloat;
  2924. typedef struct __GLsync * GLsync;
  2925. typedef int GLint;
  2926. #define GL_INT_2_10_10_10_REV 0x8D9F
  2927. #define GL_R32F 0x822E
  2928. #define GL_PROGRAM_POINT_SIZE 0x8642
  2929. #define GL_STENCIL_ATTACHMENT 0x8D20
  2930. #define GL_DEPTH_ATTACHMENT 0x8D00
  2931. #define GL_COLOR_ATTACHMENT2 0x8CE2
  2932. #define GL_COLOR_ATTACHMENT0 0x8CE0
  2933. #define GL_R16F 0x822D
  2934. #define GL_COLOR_ATTACHMENT22 0x8CF6
  2935. #define GL_DRAW_FRAMEBUFFER 0x8CA9
  2936. #define GL_FRAMEBUFFER_COMPLETE 0x8CD5
  2937. #define GL_NUM_EXTENSIONS 0x821D
  2938. #define GL_INFO_LOG_LENGTH 0x8B84
  2939. #define GL_VERTEX_SHADER 0x8B31
  2940. #define GL_INCR 0x1E02
  2941. #define GL_DYNAMIC_DRAW 0x88E8
  2942. #define GL_STATIC_DRAW 0x88E4
  2943. #define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519
  2944. #define GL_TEXTURE_CUBE_MAP 0x8513
  2945. #define GL_FUNC_SUBTRACT 0x800A
  2946. #define GL_FUNC_REVERSE_SUBTRACT 0x800B
  2947. #define GL_CONSTANT_COLOR 0x8001
  2948. #define GL_DECR_WRAP 0x8508
  2949. #define GL_R8 0x8229
  2950. #define GL_LINEAR_MIPMAP_LINEAR 0x2703
  2951. #define GL_ELEMENT_ARRAY_BUFFER 0x8893
  2952. #define GL_SHORT 0x1402
  2953. #define GL_DEPTH_TEST 0x0B71
  2954. #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518
  2955. #define GL_LINK_STATUS 0x8B82
  2956. #define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517
  2957. #define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E
  2958. #define GL_RGBA16F 0x881A
  2959. #define GL_CONSTANT_ALPHA 0x8003
  2960. #define GL_READ_FRAMEBUFFER 0x8CA8
  2961. #define GL_TEXTURE0 0x84C0
  2962. #define GL_TEXTURE_MIN_LOD 0x813A
  2963. #define GL_CLAMP_TO_EDGE 0x812F
  2964. #define GL_UNSIGNED_SHORT_5_6_5 0x8363
  2965. #define GL_TEXTURE_WRAP_R 0x8072
  2966. #define GL_UNSIGNED_SHORT_5_5_5_1 0x8034
  2967. #define GL_NEAREST_MIPMAP_NEAREST 0x2700
  2968. #define GL_UNSIGNED_SHORT_4_4_4_4 0x8033
  2969. #define GL_SRC_ALPHA_SATURATE 0x0308
  2970. #define GL_STREAM_DRAW 0x88E0
  2971. #define GL_ONE 1
  2972. #define GL_NEAREST_MIPMAP_LINEAR 0x2702
  2973. #define GL_RGB10_A2 0x8059
  2974. #define GL_RGBA8 0x8058
  2975. #define GL_COLOR_ATTACHMENT1 0x8CE1
  2976. #define GL_RGBA4 0x8056
  2977. #define GL_RGB8 0x8051
  2978. #define GL_ARRAY_BUFFER 0x8892
  2979. #define GL_STENCIL 0x1802
  2980. #define GL_TEXTURE_2D 0x0DE1
  2981. #define GL_DEPTH 0x1801
  2982. #define GL_FRONT 0x0404
  2983. #define GL_STENCIL_BUFFER_BIT 0x00000400
  2984. #define GL_REPEAT 0x2901
  2985. #define GL_RGBA 0x1908
  2986. #define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515
  2987. #define GL_DECR 0x1E03
  2988. #define GL_FRAGMENT_SHADER 0x8B30
  2989. #define GL_FLOAT 0x1406
  2990. #define GL_TEXTURE_MAX_LOD 0x813B
  2991. #define GL_DEPTH_COMPONENT 0x1902
  2992. #define GL_ONE_MINUS_DST_ALPHA 0x0305
  2993. #define GL_COLOR 0x1800
  2994. #define GL_TEXTURE_2D_ARRAY 0x8C1A
  2995. #define GL_TRIANGLES 0x0004
  2996. #define GL_UNSIGNED_BYTE 0x1401
  2997. #define GL_TEXTURE_MAG_FILTER 0x2800
  2998. #define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004
  2999. #define GL_NONE 0
  3000. #define GL_SRC_COLOR 0x0300
  3001. #define GL_BYTE 0x1400
  3002. #define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A
  3003. #define GL_LINE_STRIP 0x0003
  3004. #define GL_TEXTURE_3D 0x806F
  3005. #define GL_CW 0x0900
  3006. #define GL_LINEAR 0x2601
  3007. #define GL_RENDERBUFFER 0x8D41
  3008. #define GL_GEQUAL 0x0206
  3009. #define GL_COLOR_BUFFER_BIT 0x00004000
  3010. #define GL_RGBA32F 0x8814
  3011. #define GL_BLEND 0x0BE2
  3012. #define GL_ONE_MINUS_SRC_ALPHA 0x0303
  3013. #define GL_ONE_MINUS_CONSTANT_COLOR 0x8002
  3014. #define GL_TEXTURE_WRAP_T 0x2803
  3015. #define GL_TEXTURE_WRAP_S 0x2802
  3016. #define GL_TEXTURE_MIN_FILTER 0x2801
  3017. #define GL_LINEAR_MIPMAP_NEAREST 0x2701
  3018. #define GL_EXTENSIONS 0x1F03
  3019. #define GL_NO_ERROR 0
  3020. #define GL_REPLACE 0x1E01
  3021. #define GL_KEEP 0x1E00
  3022. #define GL_CCW 0x0901
  3023. #define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516
  3024. #define GL_RGB 0x1907
  3025. #define GL_TRIANGLE_STRIP 0x0005
  3026. #define GL_FALSE 0
  3027. #define GL_ZERO 0
  3028. #define GL_CULL_FACE 0x0B44
  3029. #define GL_INVERT 0x150A
  3030. #define GL_INT 0x1404
  3031. #define GL_UNSIGNED_INT 0x1405
  3032. #define GL_UNSIGNED_SHORT 0x1403
  3033. #define GL_NEAREST 0x2600
  3034. #define GL_SCISSOR_TEST 0x0C11
  3035. #define GL_LEQUAL 0x0203
  3036. #define GL_STENCIL_TEST 0x0B90
  3037. #define GL_DITHER 0x0BD0
  3038. #define GL_DEPTH_COMPONENT16 0x81A5
  3039. #define GL_EQUAL 0x0202
  3040. #define GL_FRAMEBUFFER 0x8D40
  3041. #define GL_RGB5 0x8050
  3042. #define GL_LINES 0x0001
  3043. #define GL_DEPTH_BUFFER_BIT 0x00000100
  3044. #define GL_SRC_ALPHA 0x0302
  3045. #define GL_INCR_WRAP 0x8507
  3046. #define GL_LESS 0x0201
  3047. #define GL_MULTISAMPLE 0x809D
  3048. #define GL_FRAMEBUFFER_BINDING 0x8CA6
  3049. #define GL_BACK 0x0405
  3050. #define GL_ALWAYS 0x0207
  3051. #define GL_FUNC_ADD 0x8006
  3052. #define GL_ONE_MINUS_DST_COLOR 0x0307
  3053. #define GL_NOTEQUAL 0x0205
  3054. #define GL_DST_COLOR 0x0306
  3055. #define GL_COMPILE_STATUS 0x8B81
  3056. #define GL_RED 0x1903
  3057. #define GL_COLOR_ATTACHMENT3 0x8CE3
  3058. #define GL_DST_ALPHA 0x0304
  3059. #define GL_RGB5_A1 0x8057
  3060. #define GL_GREATER 0x0204
  3061. #define GL_POLYGON_OFFSET_FILL 0x8037
  3062. #define GL_TRUE 1
  3063. #define GL_NEVER 0x0200
  3064. #define GL_POINTS 0x0000
  3065. #define GL_ONE_MINUS_SRC_COLOR 0x0301
  3066. #define GL_MIRRORED_REPEAT 0x8370
  3067. #define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
  3068. #define GL_R11F_G11F_B10F 0x8C3A
  3069. #define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B
  3070. #define GL_RGBA32UI 0x8D70
  3071. #define GL_RGB32UI 0x8D71
  3072. #define GL_RGBA16UI 0x8D76
  3073. #define GL_RGB16UI 0x8D77
  3074. #define GL_RGBA8UI 0x8D7C
  3075. #define GL_RGB8UI 0x8D7D
  3076. #define GL_RGBA32I 0x8D82
  3077. #define GL_RGB32I 0x8D83
  3078. #define GL_RGBA16I 0x8D88
  3079. #define GL_RGB16I 0x8D89
  3080. #define GL_RGBA8I 0x8D8E
  3081. #define GL_RGB8I 0x8D8F
  3082. #define GL_RED_INTEGER 0x8D94
  3083. #define GL_RG 0x8227
  3084. #define GL_RG_INTEGER 0x8228
  3085. #define GL_R8 0x8229
  3086. #define GL_R16 0x822A
  3087. #define GL_RG8 0x822B
  3088. #define GL_RG16 0x822C
  3089. #define GL_R16F 0x822D
  3090. #define GL_R32F 0x822E
  3091. #define GL_RG16F 0x822F
  3092. #define GL_RG32F 0x8230
  3093. #define GL_R8I 0x8231
  3094. #define GL_R8UI 0x8232
  3095. #define GL_R16I 0x8233
  3096. #define GL_R16UI 0x8234
  3097. #define GL_R32I 0x8235
  3098. #define GL_R32UI 0x8236
  3099. #define GL_RG8I 0x8237
  3100. #define GL_RG8UI 0x8238
  3101. #define GL_RG16I 0x8239
  3102. #define GL_RG16UI 0x823A
  3103. #define GL_RG32I 0x823B
  3104. #define GL_RG32UI 0x823C
  3105. #define GL_RGBA_INTEGER 0x8D99
  3106. #define GL_R8_SNORM 0x8F94
  3107. #define GL_RG8_SNORM 0x8F95
  3108. #define GL_RGB8_SNORM 0x8F96
  3109. #define GL_RGBA8_SNORM 0x8F97
  3110. #define GL_R16_SNORM 0x8F98
  3111. #define GL_RG16_SNORM 0x8F99
  3112. #define GL_RGB16_SNORM 0x8F9A
  3113. #define GL_RGBA16_SNORM 0x8F9B
  3114. #define GL_RGBA16 0x805B
  3115. #define GL_MAX_TEXTURE_SIZE 0x0D33
  3116. #define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C
  3117. #define GL_MAX_3D_TEXTURE_SIZE 0x8073
  3118. #define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF
  3119. #define GL_MAX_VERTEX_ATTRIBS 0x8869
  3120. #define GL_CLAMP_TO_BORDER 0x812D
  3121. #define GL_TEXTURE_BORDER_COLOR 0x1004
  3122. typedef void (GL_APIENTRY *PFN_glBindVertexArray)(GLuint array);
  3123. static PFN_glBindVertexArray _sapp_glBindVertexArray;
  3124. typedef void (GL_APIENTRY *PFN_glFramebufferTextureLayer)(GLenum target, GLenum attachment, GLuint texture, GLint level, GLint layer);
  3125. static PFN_glFramebufferTextureLayer _sapp_glFramebufferTextureLayer;
  3126. typedef void (GL_APIENTRY *PFN_glGenFramebuffers)(GLsizei n, GLuint * framebuffers);
  3127. static PFN_glGenFramebuffers _sapp_glGenFramebuffers;
  3128. typedef void (GL_APIENTRY *PFN_glBindFramebuffer)(GLenum target, GLuint framebuffer);
  3129. static PFN_glBindFramebuffer _sapp_glBindFramebuffer;
  3130. typedef void (GL_APIENTRY *PFN_glBindRenderbuffer)(GLenum target, GLuint renderbuffer);
  3131. static PFN_glBindRenderbuffer _sapp_glBindRenderbuffer;
  3132. typedef const GLubyte * (GL_APIENTRY *PFN_glGetStringi)(GLenum name, GLuint index);
  3133. static PFN_glGetStringi _sapp_glGetStringi;
  3134. typedef void (GL_APIENTRY *PFN_glClearBufferfi)(GLenum buffer, GLint drawbuffer, GLfloat depth, GLint stencil);
  3135. static PFN_glClearBufferfi _sapp_glClearBufferfi;
  3136. typedef void (GL_APIENTRY *PFN_glClearBufferfv)(GLenum buffer, GLint drawbuffer, const GLfloat * value);
  3137. static PFN_glClearBufferfv _sapp_glClearBufferfv;
  3138. typedef void (GL_APIENTRY *PFN_glClearBufferuiv)(GLenum buffer, GLint drawbuffer, const GLuint * value);
  3139. static PFN_glClearBufferuiv _sapp_glClearBufferuiv;
  3140. typedef void (GL_APIENTRY *PFN_glDeleteRenderbuffers)(GLsizei n, const GLuint * renderbuffers);
  3141. static PFN_glDeleteRenderbuffers _sapp_glDeleteRenderbuffers;
  3142. typedef void (GL_APIENTRY *PFN_glUniform4fv)(GLint location, GLsizei count, const GLfloat * value);
  3143. static PFN_glUniform4fv _sapp_glUniform4fv;
  3144. typedef void (GL_APIENTRY *PFN_glUniform2fv)(GLint location, GLsizei count, const GLfloat * value);
  3145. static PFN_glUniform2fv _sapp_glUniform2fv;
  3146. typedef void (GL_APIENTRY *PFN_glUseProgram)(GLuint program);
  3147. static PFN_glUseProgram _sapp_glUseProgram;
  3148. typedef void (GL_APIENTRY *PFN_glShaderSource)(GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length);
  3149. static PFN_glShaderSource _sapp_glShaderSource;
  3150. typedef void (GL_APIENTRY *PFN_glLinkProgram)(GLuint program);
  3151. static PFN_glLinkProgram _sapp_glLinkProgram;
  3152. typedef GLint (GL_APIENTRY *PFN_glGetUniformLocation)(GLuint program, const GLchar * name);
  3153. static PFN_glGetUniformLocation _sapp_glGetUniformLocation;
  3154. typedef void (GL_APIENTRY *PFN_glGetShaderiv)(GLuint shader, GLenum pname, GLint * params);
  3155. static PFN_glGetShaderiv _sapp_glGetShaderiv;
  3156. typedef void (GL_APIENTRY *PFN_glGetProgramInfoLog)(GLuint program, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
  3157. static PFN_glGetProgramInfoLog _sapp_glGetProgramInfoLog;
  3158. typedef GLint (GL_APIENTRY *PFN_glGetAttribLocation)(GLuint program, const GLchar * name);
  3159. static PFN_glGetAttribLocation _sapp_glGetAttribLocation;
  3160. typedef void (GL_APIENTRY *PFN_glDisableVertexAttribArray)(GLuint index);
  3161. static PFN_glDisableVertexAttribArray _sapp_glDisableVertexAttribArray;
  3162. typedef void (GL_APIENTRY *PFN_glDeleteShader)(GLuint shader);
  3163. static PFN_glDeleteShader _sapp_glDeleteShader;
  3164. typedef void (GL_APIENTRY *PFN_glDeleteProgram)(GLuint program);
  3165. static PFN_glDeleteProgram _sapp_glDeleteProgram;
  3166. typedef void (GL_APIENTRY *PFN_glCompileShader)(GLuint shader);
  3167. static PFN_glCompileShader _sapp_glCompileShader;
  3168. typedef void (GL_APIENTRY *PFN_glStencilFuncSeparate)(GLenum face, GLenum func, GLint ref, GLuint mask);
  3169. static PFN_glStencilFuncSeparate _sapp_glStencilFuncSeparate;
  3170. typedef void (GL_APIENTRY *PFN_glStencilOpSeparate)(GLenum face, GLenum sfail, GLenum dpfail, GLenum dppass);
  3171. static PFN_glStencilOpSeparate _sapp_glStencilOpSeparate;
  3172. typedef void (GL_APIENTRY *PFN_glRenderbufferStorageMultisample)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height);
  3173. static PFN_glRenderbufferStorageMultisample _sapp_glRenderbufferStorageMultisample;
  3174. typedef void (GL_APIENTRY *PFN_glDrawBuffers)(GLsizei n, const GLenum * bufs);
  3175. static PFN_glDrawBuffers _sapp_glDrawBuffers;
  3176. typedef void (GL_APIENTRY *PFN_glVertexAttribDivisor)(GLuint index, GLuint divisor);
  3177. static PFN_glVertexAttribDivisor _sapp_glVertexAttribDivisor;
  3178. typedef void (GL_APIENTRY *PFN_glBufferSubData)(GLenum target, GLintptr offset, GLsizeiptr size, const void * data);
  3179. static PFN_glBufferSubData _sapp_glBufferSubData;
  3180. typedef void (GL_APIENTRY *PFN_glGenBuffers)(GLsizei n, GLuint * buffers);
  3181. static PFN_glGenBuffers _sapp_glGenBuffers;
  3182. typedef GLenum (GL_APIENTRY *PFN_glCheckFramebufferStatus)(GLenum target);
  3183. static PFN_glCheckFramebufferStatus _sapp_glCheckFramebufferStatus;
  3184. typedef void (GL_APIENTRY *PFN_glFramebufferRenderbuffer)(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
  3185. static PFN_glFramebufferRenderbuffer _sapp_glFramebufferRenderbuffer;
  3186. typedef void (GL_APIENTRY *PFN_glCompressedTexImage2D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void * data);
  3187. static PFN_glCompressedTexImage2D _sapp_glCompressedTexImage2D;
  3188. typedef void (GL_APIENTRY *PFN_glCompressedTexImage3D)(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data);
  3189. static PFN_glCompressedTexImage3D _sapp_glCompressedTexImage3D;
  3190. typedef void (GL_APIENTRY *PFN_glActiveTexture)(GLenum texture);
  3191. static PFN_glActiveTexture _sapp_glActiveTexture;
  3192. typedef void (GL_APIENTRY *PFN_glTexSubImage3D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels);
  3193. static PFN_glTexSubImage3D _sapp_glTexSubImage3D;
  3194. typedef void (GL_APIENTRY *PFN_glUniformMatrix4fv)(GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
  3195. static PFN_glUniformMatrix4fv _sapp_glUniformMatrix4fv;
  3196. typedef void (GL_APIENTRY *PFN_glRenderbufferStorage)(GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
  3197. static PFN_glRenderbufferStorage _sapp_glRenderbufferStorage;
  3198. typedef void (GL_APIENTRY *PFN_glGenTextures)(GLsizei n, GLuint * textures);
  3199. static PFN_glGenTextures _sapp_glGenTextures;
  3200. typedef void (GL_APIENTRY *PFN_glPolygonOffset)(GLfloat factor, GLfloat units);
  3201. static PFN_glPolygonOffset _sapp_glPolygonOffset;
  3202. typedef void (GL_APIENTRY *PFN_glDrawElements)(GLenum mode, GLsizei count, GLenum type, const void * indices);
  3203. static PFN_glDrawElements _sapp_glDrawElements;
  3204. typedef void (GL_APIENTRY *PFN_glDeleteFramebuffers)(GLsizei n, const GLuint * framebuffers);
  3205. static PFN_glDeleteFramebuffers _sapp_glDeleteFramebuffers;
  3206. typedef void (GL_APIENTRY *PFN_glBlendEquationSeparate)(GLenum modeRGB, GLenum modeAlpha);
  3207. static PFN_glBlendEquationSeparate _sapp_glBlendEquationSeparate;
  3208. typedef void (GL_APIENTRY *PFN_glDeleteTextures)(GLsizei n, const GLuint * textures);
  3209. static PFN_glDeleteTextures _sapp_glDeleteTextures;
  3210. typedef void (GL_APIENTRY *PFN_glGetProgramiv)(GLuint program, GLenum pname, GLint * params);
  3211. static PFN_glGetProgramiv _sapp_glGetProgramiv;
  3212. typedef void (GL_APIENTRY *PFN_glBindTexture)(GLenum target, GLuint texture);
  3213. static PFN_glBindTexture _sapp_glBindTexture;
  3214. typedef void (GL_APIENTRY *PFN_glTexImage3D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void * pixels);
  3215. static PFN_glTexImage3D _sapp_glTexImage3D;
  3216. typedef GLuint (GL_APIENTRY *PFN_glCreateShader)(GLenum type);
  3217. static PFN_glCreateShader _sapp_glCreateShader;
  3218. typedef void (GL_APIENTRY *PFN_glTexSubImage2D)(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void * pixels);
  3219. static PFN_glTexSubImage2D _sapp_glTexSubImage2D;
  3220. typedef void (GL_APIENTRY *PFN_glClearDepth)(GLdouble depth);
  3221. static PFN_glClearDepth _sapp_glClearDepth;
  3222. typedef void (GL_APIENTRY *PFN_glFramebufferTexture2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
  3223. static PFN_glFramebufferTexture2D _sapp_glFramebufferTexture2D;
  3224. typedef GLuint (GL_APIENTRY *PFN_glCreateProgram)();
  3225. static PFN_glCreateProgram _sapp_glCreateProgram;
  3226. typedef void (GL_APIENTRY *PFN_glViewport)(GLint x, GLint y, GLsizei width, GLsizei height);
  3227. static PFN_glViewport _sapp_glViewport;
  3228. typedef void (GL_APIENTRY *PFN_glDeleteBuffers)(GLsizei n, const GLuint * buffers);
  3229. static PFN_glDeleteBuffers _sapp_glDeleteBuffers;
  3230. typedef void (GL_APIENTRY *PFN_glDrawArrays)(GLenum mode, GLint first, GLsizei count);
  3231. static PFN_glDrawArrays _sapp_glDrawArrays;
  3232. typedef void (GL_APIENTRY *PFN_glDrawElementsInstanced)(GLenum mode, GLsizei count, GLenum type, const void * indices, GLsizei instancecount);
  3233. static PFN_glDrawElementsInstanced _sapp_glDrawElementsInstanced;
  3234. typedef void (GL_APIENTRY *PFN_glVertexAttribPointer)(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void * pointer);
  3235. static PFN_glVertexAttribPointer _sapp_glVertexAttribPointer;
  3236. typedef void (GL_APIENTRY *PFN_glUniform1i)(GLint location, GLint v0);
  3237. static PFN_glUniform1i _sapp_glUniform1i;
  3238. typedef void (GL_APIENTRY *PFN_glDisable)(GLenum cap);
  3239. static PFN_glDisable _sapp_glDisable;
  3240. typedef void (GL_APIENTRY *PFN_glColorMask)(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
  3241. static PFN_glColorMask _sapp_glColorMask;
  3242. typedef void (GL_APIENTRY *PFN_glBindBuffer)(GLenum target, GLuint buffer);
  3243. static PFN_glBindBuffer _sapp_glBindBuffer;
  3244. typedef void (GL_APIENTRY *PFN_glDeleteVertexArrays)(GLsizei n, const GLuint * arrays);
  3245. static PFN_glDeleteVertexArrays _sapp_glDeleteVertexArrays;
  3246. typedef void (GL_APIENTRY *PFN_glDepthMask)(GLboolean flag);
  3247. static PFN_glDepthMask _sapp_glDepthMask;
  3248. typedef void (GL_APIENTRY *PFN_glDrawArraysInstanced)(GLenum mode, GLint first, GLsizei count, GLsizei instancecount);
  3249. static PFN_glDrawArraysInstanced _sapp_glDrawArraysInstanced;
  3250. typedef void (GL_APIENTRY *PFN_glClearStencil)(GLint s);
  3251. static PFN_glClearStencil _sapp_glClearStencil;
  3252. typedef void (GL_APIENTRY *PFN_glScissor)(GLint x, GLint y, GLsizei width, GLsizei height);
  3253. static PFN_glScissor _sapp_glScissor;
  3254. typedef void (GL_APIENTRY *PFN_glUniform3fv)(GLint location, GLsizei count, const GLfloat * value);
  3255. static PFN_glUniform3fv _sapp_glUniform3fv;
  3256. typedef void (GL_APIENTRY *PFN_glGenRenderbuffers)(GLsizei n, GLuint * renderbuffers);
  3257. static PFN_glGenRenderbuffers _sapp_glGenRenderbuffers;
  3258. typedef void (GL_APIENTRY *PFN_glBufferData)(GLenum target, GLsizeiptr size, const void * data, GLenum usage);
  3259. static PFN_glBufferData _sapp_glBufferData;
  3260. typedef void (GL_APIENTRY *PFN_glBlendFuncSeparate)(GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha);
  3261. static PFN_glBlendFuncSeparate _sapp_glBlendFuncSeparate;
  3262. typedef void (GL_APIENTRY *PFN_glTexParameteri)(GLenum target, GLenum pname, GLint param);
  3263. static PFN_glTexParameteri _sapp_glTexParameteri;
  3264. typedef void (GL_APIENTRY *PFN_glGetIntegerv)(GLenum pname, GLint * data);
  3265. static PFN_glGetIntegerv _sapp_glGetIntegerv;
  3266. typedef void (GL_APIENTRY *PFN_glEnable)(GLenum cap);
  3267. static PFN_glEnable _sapp_glEnable;
  3268. typedef void (GL_APIENTRY *PFN_glBlitFramebuffer)(GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1, GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1, GLbitfield mask, GLenum filter);
  3269. static PFN_glBlitFramebuffer _sapp_glBlitFramebuffer;
  3270. typedef void (GL_APIENTRY *PFN_glStencilMask)(GLuint mask);
  3271. static PFN_glStencilMask _sapp_glStencilMask;
  3272. typedef void (GL_APIENTRY *PFN_glAttachShader)(GLuint program, GLuint shader);
  3273. static PFN_glAttachShader _sapp_glAttachShader;
  3274. typedef GLenum (GL_APIENTRY *PFN_glGetError)();
  3275. static PFN_glGetError _sapp_glGetError;
  3276. typedef void (GL_APIENTRY *PFN_glClearColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
  3277. static PFN_glClearColor _sapp_glClearColor;
  3278. typedef void (GL_APIENTRY *PFN_glBlendColor)(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
  3279. static PFN_glBlendColor _sapp_glBlendColor;
  3280. typedef void (GL_APIENTRY *PFN_glTexParameterf)(GLenum target, GLenum pname, GLfloat param);
  3281. static PFN_glTexParameterf _sapp_glTexParameterf;
  3282. typedef void (GL_APIENTRY *PFN_glTexParameterfv)(GLenum target, GLenum pname, GLfloat* params);
  3283. static PFN_glTexParameterfv _sapp_glTexParameterfv;
  3284. typedef void (GL_APIENTRY *PFN_glGetShaderInfoLog)(GLuint shader, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
  3285. static PFN_glGetShaderInfoLog _sapp_glGetShaderInfoLog;
  3286. typedef void (GL_APIENTRY *PFN_glDepthFunc)(GLenum func);
  3287. static PFN_glDepthFunc _sapp_glDepthFunc;
  3288. typedef void (GL_APIENTRY *PFN_glStencilOp)(GLenum fail, GLenum zfail, GLenum zpass);
  3289. static PFN_glStencilOp _sapp_glStencilOp;
  3290. typedef void (GL_APIENTRY *PFN_glStencilFunc)(GLenum func, GLint ref, GLuint mask);
  3291. static PFN_glStencilFunc _sapp_glStencilFunc;
  3292. typedef void (GL_APIENTRY *PFN_glEnableVertexAttribArray)(GLuint index);
  3293. static PFN_glEnableVertexAttribArray _sapp_glEnableVertexAttribArray;
  3294. typedef void (GL_APIENTRY *PFN_glBlendFunc)(GLenum sfactor, GLenum dfactor);
  3295. static PFN_glBlendFunc _sapp_glBlendFunc;
  3296. typedef void (GL_APIENTRY *PFN_glUniform1fv)(GLint location, GLsizei count, const GLfloat * value);
  3297. static PFN_glUniform1fv _sapp_glUniform1fv;
  3298. typedef void (GL_APIENTRY *PFN_glReadBuffer)(GLenum src);
  3299. static PFN_glReadBuffer _sapp_glReadBuffer;
  3300. typedef void (GL_APIENTRY *PFN_glClear)(GLbitfield mask);
  3301. static PFN_glClear _sapp_glClear;
  3302. typedef void (GL_APIENTRY *PFN_glTexImage2D)(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * pixels);
  3303. static PFN_glTexImage2D _sapp_glTexImage2D;
  3304. typedef void (GL_APIENTRY *PFN_glGenVertexArrays)(GLsizei n, GLuint * arrays);
  3305. static PFN_glGenVertexArrays _sapp_glGenVertexArrays;
  3306. typedef void (GL_APIENTRY *PFN_glFrontFace)(GLenum mode);
  3307. static PFN_glFrontFace _sapp_glFrontFace;
  3308. typedef void (GL_APIENTRY *PFN_glCullFace)(GLenum mode);
  3309. static PFN_glCullFace _sapp_glCullFace;
  3310. _SOKOL_PRIVATE void* _sapp_win32_glgetprocaddr(const char* name) {
  3311. void* proc_addr = (void*) _sapp_wglGetProcAddress(name);
  3312. if (0 == proc_addr) {
  3313. proc_addr = (void*) GetProcAddress(_sapp_opengl32, name);
  3314. }
  3315. SOKOL_ASSERT(proc_addr);
  3316. return proc_addr;
  3317. }
  3318. #define _SAPP_GLPROC(name) _sapp_ ## name = (PFN_ ## name) _sapp_win32_glgetprocaddr(#name)
  3319. _SOKOL_PRIVATE void _sapp_win32_gl_loadfuncs(void) {
  3320. SOKOL_ASSERT(_sapp_wglGetProcAddress);
  3321. SOKOL_ASSERT(_sapp_opengl32);
  3322. _SAPP_GLPROC(glBindVertexArray);
  3323. _SAPP_GLPROC(glFramebufferTextureLayer);
  3324. _SAPP_GLPROC(glGenFramebuffers);
  3325. _SAPP_GLPROC(glBindFramebuffer);
  3326. _SAPP_GLPROC(glBindRenderbuffer);
  3327. _SAPP_GLPROC(glGetStringi);
  3328. _SAPP_GLPROC(glClearBufferfi);
  3329. _SAPP_GLPROC(glClearBufferfv);
  3330. _SAPP_GLPROC(glClearBufferuiv);
  3331. _SAPP_GLPROC(glDeleteRenderbuffers);
  3332. _SAPP_GLPROC(glUniform4fv);
  3333. _SAPP_GLPROC(glUniform2fv);
  3334. _SAPP_GLPROC(glUseProgram);
  3335. _SAPP_GLPROC(glShaderSource);
  3336. _SAPP_GLPROC(glLinkProgram);
  3337. _SAPP_GLPROC(glGetUniformLocation);
  3338. _SAPP_GLPROC(glGetShaderiv);
  3339. _SAPP_GLPROC(glGetProgramInfoLog);
  3340. _SAPP_GLPROC(glGetAttribLocation);
  3341. _SAPP_GLPROC(glDisableVertexAttribArray);
  3342. _SAPP_GLPROC(glDeleteShader);
  3343. _SAPP_GLPROC(glDeleteProgram);
  3344. _SAPP_GLPROC(glCompileShader);
  3345. _SAPP_GLPROC(glStencilFuncSeparate);
  3346. _SAPP_GLPROC(glStencilOpSeparate);
  3347. _SAPP_GLPROC(glRenderbufferStorageMultisample);
  3348. _SAPP_GLPROC(glDrawBuffers);
  3349. _SAPP_GLPROC(glVertexAttribDivisor);
  3350. _SAPP_GLPROC(glBufferSubData);
  3351. _SAPP_GLPROC(glGenBuffers);
  3352. _SAPP_GLPROC(glCheckFramebufferStatus);
  3353. _SAPP_GLPROC(glFramebufferRenderbuffer);
  3354. _SAPP_GLPROC(glCompressedTexImage2D);
  3355. _SAPP_GLPROC(glCompressedTexImage3D);
  3356. _SAPP_GLPROC(glActiveTexture);
  3357. _SAPP_GLPROC(glTexSubImage3D);
  3358. _SAPP_GLPROC(glUniformMatrix4fv);
  3359. _SAPP_GLPROC(glRenderbufferStorage);
  3360. _SAPP_GLPROC(glGenTextures);
  3361. _SAPP_GLPROC(glPolygonOffset);
  3362. _SAPP_GLPROC(glDrawElements);
  3363. _SAPP_GLPROC(glDeleteFramebuffers);
  3364. _SAPP_GLPROC(glBlendEquationSeparate);
  3365. _SAPP_GLPROC(glDeleteTextures);
  3366. _SAPP_GLPROC(glGetProgramiv);
  3367. _SAPP_GLPROC(glBindTexture);
  3368. _SAPP_GLPROC(glTexImage3D);
  3369. _SAPP_GLPROC(glCreateShader);
  3370. _SAPP_GLPROC(glTexSubImage2D);
  3371. _SAPP_GLPROC(glClearDepth);
  3372. _SAPP_GLPROC(glFramebufferTexture2D);
  3373. _SAPP_GLPROC(glCreateProgram);
  3374. _SAPP_GLPROC(glViewport);
  3375. _SAPP_GLPROC(glDeleteBuffers);
  3376. _SAPP_GLPROC(glDrawArrays);
  3377. _SAPP_GLPROC(glDrawElementsInstanced);
  3378. _SAPP_GLPROC(glVertexAttribPointer);
  3379. _SAPP_GLPROC(glUniform1i);
  3380. _SAPP_GLPROC(glDisable);
  3381. _SAPP_GLPROC(glColorMask);
  3382. _SAPP_GLPROC(glBindBuffer);
  3383. _SAPP_GLPROC(glDeleteVertexArrays);
  3384. _SAPP_GLPROC(glDepthMask);
  3385. _SAPP_GLPROC(glDrawArraysInstanced);
  3386. _SAPP_GLPROC(glClearStencil);
  3387. _SAPP_GLPROC(glScissor);
  3388. _SAPP_GLPROC(glUniform3fv);
  3389. _SAPP_GLPROC(glGenRenderbuffers);
  3390. _SAPP_GLPROC(glBufferData);
  3391. _SAPP_GLPROC(glBlendFuncSeparate);
  3392. _SAPP_GLPROC(glTexParameteri);
  3393. _SAPP_GLPROC(glGetIntegerv);
  3394. _SAPP_GLPROC(glEnable);
  3395. _SAPP_GLPROC(glBlitFramebuffer);
  3396. _SAPP_GLPROC(glStencilMask);
  3397. _SAPP_GLPROC(glAttachShader);
  3398. _SAPP_GLPROC(glGetError);
  3399. _SAPP_GLPROC(glClearColor);
  3400. _SAPP_GLPROC(glBlendColor);
  3401. _SAPP_GLPROC(glTexParameterf);
  3402. _SAPP_GLPROC(glTexParameterfv);
  3403. _SAPP_GLPROC(glGetShaderInfoLog);
  3404. _SAPP_GLPROC(glDepthFunc);
  3405. _SAPP_GLPROC(glStencilOp);
  3406. _SAPP_GLPROC(glStencilFunc);
  3407. _SAPP_GLPROC(glEnableVertexAttribArray);
  3408. _SAPP_GLPROC(glBlendFunc);
  3409. _SAPP_GLPROC(glUniform1fv);
  3410. _SAPP_GLPROC(glReadBuffer);
  3411. _SAPP_GLPROC(glClear);
  3412. _SAPP_GLPROC(glTexImage2D);
  3413. _SAPP_GLPROC(glGenVertexArrays);
  3414. _SAPP_GLPROC(glFrontFace);
  3415. _SAPP_GLPROC(glCullFace);
  3416. }
  3417. #define glBindVertexArray _sapp_glBindVertexArray
  3418. #define glFramebufferTextureLayer _sapp_glFramebufferTextureLayer
  3419. #define glGenFramebuffers _sapp_glGenFramebuffers
  3420. #define glBindFramebuffer _sapp_glBindFramebuffer
  3421. #define glBindRenderbuffer _sapp_glBindRenderbuffer
  3422. #define glGetStringi _sapp_glGetStringi
  3423. #define glClearBufferfi _sapp_glClearBufferfi
  3424. #define glClearBufferfv _sapp_glClearBufferfv
  3425. #define glClearBufferuiv _sapp_glClearBufferuiv
  3426. #define glDeleteRenderbuffers _sapp_glDeleteRenderbuffers
  3427. #define glUniform4fv _sapp_glUniform4fv
  3428. #define glUniform2fv _sapp_glUniform2fv
  3429. #define glUseProgram _sapp_glUseProgram
  3430. #define glShaderSource _sapp_glShaderSource
  3431. #define glLinkProgram _sapp_glLinkProgram
  3432. #define glGetUniformLocation _sapp_glGetUniformLocation
  3433. #define glGetShaderiv _sapp_glGetShaderiv
  3434. #define glGetProgramInfoLog _sapp_glGetProgramInfoLog
  3435. #define glGetAttribLocation _sapp_glGetAttribLocation
  3436. #define glDisableVertexAttribArray _sapp_glDisableVertexAttribArray
  3437. #define glDeleteShader _sapp_glDeleteShader
  3438. #define glDeleteProgram _sapp_glDeleteProgram
  3439. #define glCompileShader _sapp_glCompileShader
  3440. #define glStencilFuncSeparate _sapp_glStencilFuncSeparate
  3441. #define glStencilOpSeparate _sapp_glStencilOpSeparate
  3442. #define glRenderbufferStorageMultisample _sapp_glRenderbufferStorageMultisample
  3443. #define glDrawBuffers _sapp_glDrawBuffers
  3444. #define glVertexAttribDivisor _sapp_glVertexAttribDivisor
  3445. #define glBufferSubData _sapp_glBufferSubData
  3446. #define glGenBuffers _sapp_glGenBuffers
  3447. #define glCheckFramebufferStatus _sapp_glCheckFramebufferStatus
  3448. #define glFramebufferRenderbuffer _sapp_glFramebufferRenderbuffer
  3449. #define glCompressedTexImage2D _sapp_glCompressedTexImage2D
  3450. #define glCompressedTexImage3D _sapp_glCompressedTexImage3D
  3451. #define glActiveTexture _sapp_glActiveTexture
  3452. #define glTexSubImage3D _sapp_glTexSubImage3D
  3453. #define glUniformMatrix4fv _sapp_glUniformMatrix4fv
  3454. #define glRenderbufferStorage _sapp_glRenderbufferStorage
  3455. #define glGenTextures _sapp_glGenTextures
  3456. #define glPolygonOffset _sapp_glPolygonOffset
  3457. #define glDrawElements _sapp_glDrawElements
  3458. #define glDeleteFramebuffers _sapp_glDeleteFramebuffers
  3459. #define glBlendEquationSeparate _sapp_glBlendEquationSeparate
  3460. #define glDeleteTextures _sapp_glDeleteTextures
  3461. #define glGetProgramiv _sapp_glGetProgramiv
  3462. #define glBindTexture _sapp_glBindTexture
  3463. #define glTexImage3D _sapp_glTexImage3D
  3464. #define glCreateShader _sapp_glCreateShader
  3465. #define glTexSubImage2D _sapp_glTexSubImage2D
  3466. #define glClearDepth _sapp_glClearDepth
  3467. #define glFramebufferTexture2D _sapp_glFramebufferTexture2D
  3468. #define glCreateProgram _sapp_glCreateProgram
  3469. #define glViewport _sapp_glViewport
  3470. #define glDeleteBuffers _sapp_glDeleteBuffers
  3471. #define glDrawArrays _sapp_glDrawArrays
  3472. #define glDrawElementsInstanced _sapp_glDrawElementsInstanced
  3473. #define glVertexAttribPointer _sapp_glVertexAttribPointer
  3474. #define glUniform1i _sapp_glUniform1i
  3475. #define glDisable _sapp_glDisable
  3476. #define glColorMask _sapp_glColorMask
  3477. #define glBindBuffer _sapp_glBindBuffer
  3478. #define glDeleteVertexArrays _sapp_glDeleteVertexArrays
  3479. #define glDepthMask _sapp_glDepthMask
  3480. #define glDrawArraysInstanced _sapp_glDrawArraysInstanced
  3481. #define glClearStencil _sapp_glClearStencil
  3482. #define glScissor _sapp_glScissor
  3483. #define glUniform3fv _sapp_glUniform3fv
  3484. #define glGenRenderbuffers _sapp_glGenRenderbuffers
  3485. #define glBufferData _sapp_glBufferData
  3486. #define glBlendFuncSeparate _sapp_glBlendFuncSeparate
  3487. #define glTexParameteri _sapp_glTexParameteri
  3488. #define glGetIntegerv _sapp_glGetIntegerv
  3489. #define glEnable _sapp_glEnable
  3490. #define glBlitFramebuffer _sapp_glBlitFramebuffer
  3491. #define glStencilMask _sapp_glStencilMask
  3492. #define glAttachShader _sapp_glAttachShader
  3493. #define glGetError _sapp_glGetError
  3494. #define glClearColor _sapp_glClearColor
  3495. #define glBlendColor _sapp_glBlendColor
  3496. #define glTexParameterf _sapp_glTexParameterf
  3497. #define glTexParameterfv _sapp_glTexParameterfv
  3498. #define glGetShaderInfoLog _sapp_glGetShaderInfoLog
  3499. #define glDepthFunc _sapp_glDepthFunc
  3500. #define glStencilOp _sapp_glStencilOp
  3501. #define glStencilFunc _sapp_glStencilFunc
  3502. #define glEnableVertexAttribArray _sapp_glEnableVertexAttribArray
  3503. #define glBlendFunc _sapp_glBlendFunc
  3504. #define glUniform1fv _sapp_glUniform1fv
  3505. #define glReadBuffer _sapp_glReadBuffer
  3506. #define glClear _sapp_glClear
  3507. #define glTexImage2D _sapp_glTexImage2D
  3508. #define glGenVertexArrays _sapp_glGenVertexArrays
  3509. #define glFrontFace _sapp_glFrontFace
  3510. #define glCullFace _sapp_glCullFace
  3511. #endif /* SOKOL_WIN32_NO_GL_LOADER */
  3512. #endif /* SOKOL_GLCORE33 */
  3513. #if defined(SOKOL_D3D11)
  3514. #define _SAPP_SAFE_RELEASE(class, obj) if (obj) { class##_Release(obj); obj=0; }
  3515. _SOKOL_PRIVATE void _sapp_d3d11_create_device_and_swapchain(void) {
  3516. DXGI_SWAP_CHAIN_DESC* sc_desc = &_sapp_dxgi_swap_chain_desc;
  3517. sc_desc->BufferDesc.Width = _sapp.framebuffer_width;
  3518. sc_desc->BufferDesc.Height = _sapp.framebuffer_height;
  3519. sc_desc->BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
  3520. sc_desc->BufferDesc.RefreshRate.Numerator = 60;
  3521. sc_desc->BufferDesc.RefreshRate.Denominator = 1;
  3522. sc_desc->OutputWindow = _sapp_win32_hwnd;
  3523. sc_desc->Windowed = true;
  3524. sc_desc->SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
  3525. sc_desc->BufferCount = 1;
  3526. sc_desc->SampleDesc.Count = _sapp.sample_count;
  3527. sc_desc->SampleDesc.Quality = _sapp.sample_count > 1 ? D3D11_STANDARD_MULTISAMPLE_PATTERN : 0;
  3528. sc_desc->BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
  3529. int create_flags = D3D11_CREATE_DEVICE_SINGLETHREADED | D3D11_CREATE_DEVICE_BGRA_SUPPORT;
  3530. #if defined(SOKOL_DEBUG)
  3531. create_flags |= D3D11_CREATE_DEVICE_DEBUG;
  3532. #endif
  3533. D3D_FEATURE_LEVEL feature_level;
  3534. HRESULT hr = D3D11CreateDeviceAndSwapChain(
  3535. NULL, /* pAdapter (use default) */
  3536. D3D_DRIVER_TYPE_HARDWARE, /* DriverType */
  3537. NULL, /* Software */
  3538. create_flags, /* Flags */
  3539. NULL, /* pFeatureLevels */
  3540. 0, /* FeatureLevels */
  3541. D3D11_SDK_VERSION, /* SDKVersion */
  3542. sc_desc, /* pSwapChainDesc */
  3543. &_sapp_dxgi_swap_chain, /* ppSwapChain */
  3544. &_sapp_d3d11_device, /* ppDevice */
  3545. &feature_level, /* pFeatureLevel */
  3546. &_sapp_d3d11_device_context); /* ppImmediateContext */
  3547. _SOKOL_UNUSED(hr);
  3548. SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_dxgi_swap_chain && _sapp_d3d11_device && _sapp_d3d11_device_context);
  3549. }
  3550. _SOKOL_PRIVATE void _sapp_d3d11_destroy_device_and_swapchain(void) {
  3551. _SAPP_SAFE_RELEASE(IDXGISwapChain, _sapp_dxgi_swap_chain);
  3552. _SAPP_SAFE_RELEASE(ID3D11DeviceContext, _sapp_d3d11_device_context);
  3553. _SAPP_SAFE_RELEASE(ID3D11Device, _sapp_d3d11_device);
  3554. }
  3555. _SOKOL_PRIVATE void _sapp_d3d11_create_default_render_target(void) {
  3556. HRESULT hr;
  3557. #ifdef __cplusplus
  3558. hr = IDXGISwapChain_GetBuffer(_sapp_dxgi_swap_chain, 0, IID_ID3D11Texture2D, (void**)&_sapp_d3d11_rt);
  3559. #else
  3560. hr = IDXGISwapChain_GetBuffer(_sapp_dxgi_swap_chain, 0, &IID_ID3D11Texture2D, (void**)&_sapp_d3d11_rt);
  3561. #endif
  3562. SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_d3d11_rt);
  3563. hr = ID3D11Device_CreateRenderTargetView(_sapp_d3d11_device, (ID3D11Resource*)_sapp_d3d11_rt, NULL, &_sapp_d3d11_rtv);
  3564. SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_d3d11_rtv);
  3565. D3D11_TEXTURE2D_DESC ds_desc;
  3566. memset(&ds_desc, 0, sizeof(ds_desc));
  3567. ds_desc.Width = _sapp.framebuffer_width;
  3568. ds_desc.Height = _sapp.framebuffer_height;
  3569. ds_desc.MipLevels = 1;
  3570. ds_desc.ArraySize = 1;
  3571. ds_desc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
  3572. ds_desc.SampleDesc = _sapp_dxgi_swap_chain_desc.SampleDesc;
  3573. ds_desc.Usage = D3D11_USAGE_DEFAULT;
  3574. ds_desc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
  3575. hr = ID3D11Device_CreateTexture2D(_sapp_d3d11_device, &ds_desc, NULL, &_sapp_d3d11_ds);
  3576. SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_d3d11_ds);
  3577. D3D11_DEPTH_STENCIL_VIEW_DESC dsv_desc;
  3578. memset(&dsv_desc, 0, sizeof(dsv_desc));
  3579. dsv_desc.Format = ds_desc.Format;
  3580. dsv_desc.ViewDimension = _sapp.sample_count > 1 ? D3D11_DSV_DIMENSION_TEXTURE2DMS : D3D11_DSV_DIMENSION_TEXTURE2D;
  3581. hr = ID3D11Device_CreateDepthStencilView(_sapp_d3d11_device, (ID3D11Resource*)_sapp_d3d11_ds, &dsv_desc, &_sapp_d3d11_dsv);
  3582. SOKOL_ASSERT(SUCCEEDED(hr) && _sapp_d3d11_dsv);
  3583. }
  3584. _SOKOL_PRIVATE void _sapp_d3d11_destroy_default_render_target(void) {
  3585. _SAPP_SAFE_RELEASE(ID3D11Texture2D, _sapp_d3d11_rt);
  3586. _SAPP_SAFE_RELEASE(ID3D11RenderTargetView, _sapp_d3d11_rtv);
  3587. _SAPP_SAFE_RELEASE(ID3D11Texture2D, _sapp_d3d11_ds);
  3588. _SAPP_SAFE_RELEASE(ID3D11DepthStencilView, _sapp_d3d11_dsv);
  3589. }
  3590. _SOKOL_PRIVATE void _sapp_d3d11_resize_default_render_target(void) {
  3591. if (_sapp_dxgi_swap_chain) {
  3592. _sapp_d3d11_destroy_default_render_target();
  3593. IDXGISwapChain_ResizeBuffers(_sapp_dxgi_swap_chain, 1, _sapp.framebuffer_width, _sapp.framebuffer_height, DXGI_FORMAT_B8G8R8A8_UNORM, 0);
  3594. _sapp_d3d11_create_default_render_target();
  3595. }
  3596. }
  3597. #endif
  3598. #if defined(SOKOL_GLCORE33)
  3599. _SOKOL_PRIVATE void _sapp_wgl_init(void) {
  3600. _sapp_opengl32 = LoadLibraryA("opengl32.dll");
  3601. if (!_sapp_opengl32) {
  3602. _sapp_fail("Failed to load opengl32.dll\n");
  3603. }
  3604. SOKOL_ASSERT(_sapp_opengl32);
  3605. _sapp_wglCreateContext = (PFN_wglCreateContext) GetProcAddress(_sapp_opengl32, "wglCreateContext");
  3606. SOKOL_ASSERT(_sapp_wglCreateContext);
  3607. _sapp_wglDeleteContext = (PFN_wglDeleteContext) GetProcAddress(_sapp_opengl32, "wglDeleteContext");
  3608. SOKOL_ASSERT(_sapp_wglDeleteContext);
  3609. _sapp_wglGetProcAddress = (PFN_wglGetProcAddress) GetProcAddress(_sapp_opengl32, "wglGetProcAddress");
  3610. SOKOL_ASSERT(_sapp_wglGetProcAddress);
  3611. _sapp_wglGetCurrentDC = (PFN_wglGetCurrentDC) GetProcAddress(_sapp_opengl32, "wglGetCurrentDC");
  3612. SOKOL_ASSERT(_sapp_wglGetCurrentDC);
  3613. _sapp_wglMakeCurrent = (PFN_wglMakeCurrent) GetProcAddress(_sapp_opengl32, "wglMakeCurrent");
  3614. SOKOL_ASSERT(_sapp_wglMakeCurrent);
  3615. _sapp_win32_msg_hwnd = CreateWindowExW(WS_EX_OVERLAPPEDWINDOW,
  3616. L"SOKOLAPP",
  3617. L"sokol-app message window",
  3618. WS_CLIPSIBLINGS|WS_CLIPCHILDREN,
  3619. 0, 0, 1, 1,
  3620. NULL, NULL,
  3621. GetModuleHandleW(NULL),
  3622. NULL);
  3623. if (!_sapp_win32_msg_hwnd) {
  3624. _sapp_fail("Win32: failed to create helper window!\n");
  3625. }
  3626. ShowWindow(_sapp_win32_msg_hwnd, SW_HIDE);
  3627. MSG msg;
  3628. while (PeekMessageW(&msg, _sapp_win32_msg_hwnd, 0, 0, PM_REMOVE)) {
  3629. TranslateMessage(&msg);
  3630. DispatchMessageW(&msg);
  3631. }
  3632. _sapp_win32_msg_dc = GetDC(_sapp_win32_msg_hwnd);
  3633. if (!_sapp_win32_msg_dc) {
  3634. _sapp_fail("Win32: failed to obtain helper window DC!\n");
  3635. }
  3636. }
  3637. _SOKOL_PRIVATE void _sapp_wgl_shutdown(void) {
  3638. SOKOL_ASSERT(_sapp_opengl32 && _sapp_win32_msg_hwnd);
  3639. DestroyWindow(_sapp_win32_msg_hwnd); _sapp_win32_msg_hwnd = 0;
  3640. FreeLibrary(_sapp_opengl32); _sapp_opengl32 = 0;
  3641. }
  3642. _SOKOL_PRIVATE bool _sapp_wgl_has_ext(const char* ext, const char* extensions) {
  3643. SOKOL_ASSERT(ext && extensions);
  3644. const char* start = extensions;
  3645. while (true) {
  3646. const char* where = strstr(start, ext);
  3647. if (!where) {
  3648. return false;
  3649. }
  3650. const char* terminator = where + strlen(ext);
  3651. if ((where == start) || (*(where - 1) == ' ')) {
  3652. if (*terminator == ' ' || *terminator == '\0') {
  3653. break;
  3654. }
  3655. }
  3656. start = terminator;
  3657. }
  3658. return true;
  3659. }
  3660. _SOKOL_PRIVATE bool _sapp_wgl_ext_supported(const char* ext) {
  3661. SOKOL_ASSERT(ext);
  3662. if (_sapp_GetExtensionsStringEXT) {
  3663. const char* extensions = _sapp_GetExtensionsStringEXT();
  3664. if (extensions) {
  3665. if (_sapp_wgl_has_ext(ext, extensions)) {
  3666. return true;
  3667. }
  3668. }
  3669. }
  3670. if (_sapp_GetExtensionsStringARB) {
  3671. const char* extensions = _sapp_GetExtensionsStringARB(_sapp_wglGetCurrentDC());
  3672. if (extensions) {
  3673. if (_sapp_wgl_has_ext(ext, extensions)) {
  3674. return true;
  3675. }
  3676. }
  3677. }
  3678. return false;
  3679. }
  3680. _SOKOL_PRIVATE void _sapp_wgl_load_extensions(void) {
  3681. SOKOL_ASSERT(_sapp_win32_msg_dc);
  3682. PIXELFORMATDESCRIPTOR pfd;
  3683. memset(&pfd, 0, sizeof(pfd));
  3684. pfd.nSize = sizeof(pfd);
  3685. pfd.nVersion = 1;
  3686. pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
  3687. pfd.iPixelType = PFD_TYPE_RGBA;
  3688. pfd.cColorBits = 24;
  3689. if (!SetPixelFormat(_sapp_win32_msg_dc, ChoosePixelFormat(_sapp_win32_msg_dc, &pfd), &pfd)) {
  3690. _sapp_fail("WGL: failed to set pixel format for dummy context\n");
  3691. }
  3692. HGLRC rc = _sapp_wglCreateContext(_sapp_win32_msg_dc);
  3693. if (!rc) {
  3694. _sapp_fail("WGL: Failed to create dummy context\n");
  3695. }
  3696. if (!_sapp_wglMakeCurrent(_sapp_win32_msg_dc, rc)) {
  3697. _sapp_fail("WGL: Failed to make context current\n");
  3698. }
  3699. _sapp_GetExtensionsStringEXT = (PFNWGLGETEXTENSIONSSTRINGEXTPROC) _sapp_wglGetProcAddress("wglGetExtensionsStringEXT");
  3700. _sapp_GetExtensionsStringARB = (PFNWGLGETEXTENSIONSSTRINGARBPROC) _sapp_wglGetProcAddress("wglGetExtensionsStringARB");
  3701. _sapp_CreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) _sapp_wglGetProcAddress("wglCreateContextAttribsARB");
  3702. _sapp_SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) _sapp_wglGetProcAddress("wglSwapIntervalEXT");
  3703. _sapp_GetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) _sapp_wglGetProcAddress("wglGetPixelFormatAttribivARB");
  3704. _sapp_arb_multisample = _sapp_wgl_ext_supported("WGL_ARB_multisample");
  3705. _sapp_arb_create_context = _sapp_wgl_ext_supported("WGL_ARB_create_context");
  3706. _sapp_arb_create_context_profile = _sapp_wgl_ext_supported("WGL_ARB_create_context_profile");
  3707. _sapp_ext_swap_control = _sapp_wgl_ext_supported("WGL_EXT_swap_control");
  3708. _sapp_arb_pixel_format = _sapp_wgl_ext_supported("WGL_ARB_pixel_format");
  3709. _sapp_wglMakeCurrent(_sapp_win32_msg_dc, 0);
  3710. _sapp_wglDeleteContext(rc);
  3711. }
  3712. _SOKOL_PRIVATE int _sapp_wgl_attrib(int pixel_format, int attrib) {
  3713. SOKOL_ASSERT(_sapp_arb_pixel_format);
  3714. int value = 0;
  3715. if (!_sapp_GetPixelFormatAttribivARB(_sapp_win32_dc, pixel_format, 0, 1, &attrib, &value)) {
  3716. _sapp_fail("WGL: Failed to retrieve pixel format attribute\n");
  3717. }
  3718. return value;
  3719. }
  3720. _SOKOL_PRIVATE int _sapp_wgl_find_pixel_format(void) {
  3721. SOKOL_ASSERT(_sapp_win32_dc);
  3722. SOKOL_ASSERT(_sapp_arb_pixel_format);
  3723. const _sapp_gl_fbconfig* closest;
  3724. int native_count = _sapp_wgl_attrib(1, WGL_NUMBER_PIXEL_FORMATS_ARB);
  3725. _sapp_gl_fbconfig* usable_configs = (_sapp_gl_fbconfig*) SOKOL_CALLOC(native_count, sizeof(_sapp_gl_fbconfig));
  3726. int usable_count = 0;
  3727. for (int i = 0; i < native_count; i++) {
  3728. const int n = i + 1;
  3729. _sapp_gl_fbconfig* u = usable_configs + usable_count;
  3730. _sapp_gl_init_fbconfig(u);
  3731. if (!_sapp_wgl_attrib(n, WGL_SUPPORT_OPENGL_ARB) || !_sapp_wgl_attrib(n, WGL_DRAW_TO_WINDOW_ARB)) {
  3732. continue;
  3733. }
  3734. if (_sapp_wgl_attrib(n, WGL_PIXEL_TYPE_ARB) != WGL_TYPE_RGBA_ARB) {
  3735. continue;
  3736. }
  3737. if (_sapp_wgl_attrib(n, WGL_ACCELERATION_ARB) == WGL_NO_ACCELERATION_ARB) {
  3738. continue;
  3739. }
  3740. u->red_bits = _sapp_wgl_attrib(n, WGL_RED_BITS_ARB);
  3741. u->green_bits = _sapp_wgl_attrib(n, WGL_GREEN_BITS_ARB);
  3742. u->blue_bits = _sapp_wgl_attrib(n, WGL_BLUE_BITS_ARB);
  3743. u->alpha_bits = _sapp_wgl_attrib(n, WGL_ALPHA_BITS_ARB);
  3744. u->depth_bits = _sapp_wgl_attrib(n, WGL_DEPTH_BITS_ARB);
  3745. u->stencil_bits = _sapp_wgl_attrib(n, WGL_STENCIL_BITS_ARB);
  3746. if (_sapp_wgl_attrib(n, WGL_DOUBLE_BUFFER_ARB)) {
  3747. u->doublebuffer = true;
  3748. }
  3749. if (_sapp_arb_multisample) {
  3750. u->samples = _sapp_wgl_attrib(n, WGL_SAMPLES_ARB);
  3751. }
  3752. u->handle = n;
  3753. usable_count++;
  3754. }
  3755. SOKOL_ASSERT(usable_count > 0);
  3756. _sapp_gl_fbconfig desired;
  3757. _sapp_gl_init_fbconfig(&desired);
  3758. desired.red_bits = 8;
  3759. desired.green_bits = 8;
  3760. desired.blue_bits = 8;
  3761. desired.alpha_bits = 8;
  3762. desired.depth_bits = 24;
  3763. desired.stencil_bits = 8;
  3764. desired.doublebuffer = true;
  3765. desired.samples = _sapp.sample_count > 1 ? _sapp.sample_count : 0;
  3766. closest = _sapp_gl_choose_fbconfig(&desired, usable_configs, usable_count);
  3767. int pixel_format = 0;
  3768. if (closest) {
  3769. pixel_format = (int) closest->handle;
  3770. }
  3771. SOKOL_FREE(usable_configs);
  3772. return pixel_format;
  3773. }
  3774. _SOKOL_PRIVATE void _sapp_wgl_create_context(void) {
  3775. int pixel_format = _sapp_wgl_find_pixel_format();
  3776. if (0 == pixel_format) {
  3777. _sapp_fail("WGL: Didn't find matching pixel format.\n");
  3778. }
  3779. PIXELFORMATDESCRIPTOR pfd;
  3780. if (!DescribePixelFormat(_sapp_win32_dc, pixel_format, sizeof(pfd), &pfd)) {
  3781. _sapp_fail("WGL: Failed to retrieve PFD for selected pixel format!\n");
  3782. }
  3783. if (!SetPixelFormat(_sapp_win32_dc, pixel_format, &pfd)) {
  3784. _sapp_fail("WGL: Failed to set selected pixel format!\n");
  3785. }
  3786. if (!_sapp_arb_create_context) {
  3787. _sapp_fail("WGL: ARB_create_context required!\n");
  3788. }
  3789. if (!_sapp_arb_create_context_profile) {
  3790. _sapp_fail("WGL: ARB_create_context_profile required!\n");
  3791. }
  3792. const int attrs[] = {
  3793. WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
  3794. WGL_CONTEXT_MINOR_VERSION_ARB, 3,
  3795. WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
  3796. WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
  3797. 0, 0
  3798. };
  3799. _sapp_gl_ctx = _sapp_CreateContextAttribsARB(_sapp_win32_dc, 0, attrs);
  3800. if (!_sapp_gl_ctx) {
  3801. const DWORD err = GetLastError();
  3802. if (err == (0xc0070000 | ERROR_INVALID_VERSION_ARB)) {
  3803. _sapp_fail("WGL: Driver does not support OpenGL version 3.3\n");
  3804. }
  3805. else if (err == (0xc0070000 | ERROR_INVALID_PROFILE_ARB)) {
  3806. _sapp_fail("WGL: Driver does not support the requested OpenGL profile");
  3807. }
  3808. else if (err == (0xc0070000 | ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB)) {
  3809. _sapp_fail("WGL: The share context is not compatible with the requested context");
  3810. }
  3811. else {
  3812. _sapp_fail("WGL: Failed to create OpenGL context");
  3813. }
  3814. }
  3815. _sapp_wglMakeCurrent(_sapp_win32_dc, _sapp_gl_ctx);
  3816. if (_sapp_ext_swap_control) {
  3817. /* FIXME: DwmIsCompositionEnabled() (see GLFW) */
  3818. _sapp_SwapIntervalEXT(_sapp.swap_interval);
  3819. }
  3820. }
  3821. _SOKOL_PRIVATE void _sapp_wgl_destroy_context(void) {
  3822. SOKOL_ASSERT(_sapp_gl_ctx);
  3823. _sapp_wglDeleteContext(_sapp_gl_ctx);
  3824. _sapp_gl_ctx = 0;
  3825. }
  3826. _SOKOL_PRIVATE void _sapp_wgl_swap_buffers(void) {
  3827. SOKOL_ASSERT(_sapp_win32_dc);
  3828. /* FIXME: DwmIsCompositionEnabled? (see GLFW) */
  3829. SwapBuffers(_sapp_win32_dc);
  3830. }
  3831. #endif
  3832. _SOKOL_PRIVATE bool _sapp_win32_utf8_to_wide(const char* src, wchar_t* dst, int dst_num_bytes) {
  3833. SOKOL_ASSERT(src && dst && (dst_num_bytes > 1));
  3834. memset(dst, 0, dst_num_bytes);
  3835. const int dst_chars = dst_num_bytes / sizeof(wchar_t);
  3836. const int dst_needed = MultiByteToWideChar(CP_UTF8, 0, src, -1, 0, 0);
  3837. if ((dst_needed > 0) && (dst_needed < dst_chars)) {
  3838. MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, dst_chars);
  3839. return true;
  3840. }
  3841. else {
  3842. /* input string doesn't fit into destination buffer */
  3843. return false;
  3844. }
  3845. }
  3846. _SOKOL_PRIVATE bool _sapp_win32_wide_to_utf8(const wchar_t* src, char* dst, int dst_num_bytes) {
  3847. SOKOL_ASSERT(src && dst && (dst_num_bytes > 1));
  3848. memset(dst, 0, dst_num_bytes);
  3849. return 0 != WideCharToMultiByte(CP_UTF8, 0, src, -1, dst, dst_num_bytes, NULL, NULL);
  3850. }
  3851. _SOKOL_PRIVATE void _sapp_win32_show_mouse(bool shown) {
  3852. ShowCursor((BOOL)shown);
  3853. }
  3854. _SOKOL_PRIVATE bool _sapp_win32_mouse_shown(void) {
  3855. CURSORINFO cursor_info;
  3856. memset(&cursor_info, 0, sizeof(CURSORINFO));
  3857. cursor_info.cbSize = sizeof(CURSORINFO);
  3858. GetCursorInfo(&cursor_info);
  3859. return (cursor_info.flags & CURSOR_SHOWING) != 0;
  3860. }
  3861. _SOKOL_PRIVATE void _sapp_win32_init_keytable(void) {
  3862. /* same as GLFW */
  3863. _sapp.keycodes[0x00B] = SAPP_KEYCODE_0;
  3864. _sapp.keycodes[0x002] = SAPP_KEYCODE_1;
  3865. _sapp.keycodes[0x003] = SAPP_KEYCODE_2;
  3866. _sapp.keycodes[0x004] = SAPP_KEYCODE_3;
  3867. _sapp.keycodes[0x005] = SAPP_KEYCODE_4;
  3868. _sapp.keycodes[0x006] = SAPP_KEYCODE_5;
  3869. _sapp.keycodes[0x007] = SAPP_KEYCODE_6;
  3870. _sapp.keycodes[0x008] = SAPP_KEYCODE_7;
  3871. _sapp.keycodes[0x009] = SAPP_KEYCODE_8;
  3872. _sapp.keycodes[0x00A] = SAPP_KEYCODE_9;
  3873. _sapp.keycodes[0x01E] = SAPP_KEYCODE_A;
  3874. _sapp.keycodes[0x030] = SAPP_KEYCODE_B;
  3875. _sapp.keycodes[0x02E] = SAPP_KEYCODE_C;
  3876. _sapp.keycodes[0x020] = SAPP_KEYCODE_D;
  3877. _sapp.keycodes[0x012] = SAPP_KEYCODE_E;
  3878. _sapp.keycodes[0x021] = SAPP_KEYCODE_F;
  3879. _sapp.keycodes[0x022] = SAPP_KEYCODE_G;
  3880. _sapp.keycodes[0x023] = SAPP_KEYCODE_H;
  3881. _sapp.keycodes[0x017] = SAPP_KEYCODE_I;
  3882. _sapp.keycodes[0x024] = SAPP_KEYCODE_J;
  3883. _sapp.keycodes[0x025] = SAPP_KEYCODE_K;
  3884. _sapp.keycodes[0x026] = SAPP_KEYCODE_L;
  3885. _sapp.keycodes[0x032] = SAPP_KEYCODE_M;
  3886. _sapp.keycodes[0x031] = SAPP_KEYCODE_N;
  3887. _sapp.keycodes[0x018] = SAPP_KEYCODE_O;
  3888. _sapp.keycodes[0x019] = SAPP_KEYCODE_P;
  3889. _sapp.keycodes[0x010] = SAPP_KEYCODE_Q;
  3890. _sapp.keycodes[0x013] = SAPP_KEYCODE_R;
  3891. _sapp.keycodes[0x01F] = SAPP_KEYCODE_S;
  3892. _sapp.keycodes[0x014] = SAPP_KEYCODE_T;
  3893. _sapp.keycodes[0x016] = SAPP_KEYCODE_U;
  3894. _sapp.keycodes[0x02F] = SAPP_KEYCODE_V;
  3895. _sapp.keycodes[0x011] = SAPP_KEYCODE_W;
  3896. _sapp.keycodes[0x02D] = SAPP_KEYCODE_X;
  3897. _sapp.keycodes[0x015] = SAPP_KEYCODE_Y;
  3898. _sapp.keycodes[0x02C] = SAPP_KEYCODE_Z;
  3899. _sapp.keycodes[0x028] = SAPP_KEYCODE_APOSTROPHE;
  3900. _sapp.keycodes[0x02B] = SAPP_KEYCODE_BACKSLASH;
  3901. _sapp.keycodes[0x033] = SAPP_KEYCODE_COMMA;
  3902. _sapp.keycodes[0x00D] = SAPP_KEYCODE_EQUAL;
  3903. _sapp.keycodes[0x029] = SAPP_KEYCODE_GRAVE_ACCENT;
  3904. _sapp.keycodes[0x01A] = SAPP_KEYCODE_LEFT_BRACKET;
  3905. _sapp.keycodes[0x00C] = SAPP_KEYCODE_MINUS;
  3906. _sapp.keycodes[0x034] = SAPP_KEYCODE_PERIOD;
  3907. _sapp.keycodes[0x01B] = SAPP_KEYCODE_RIGHT_BRACKET;
  3908. _sapp.keycodes[0x027] = SAPP_KEYCODE_SEMICOLON;
  3909. _sapp.keycodes[0x035] = SAPP_KEYCODE_SLASH;
  3910. _sapp.keycodes[0x056] = SAPP_KEYCODE_WORLD_2;
  3911. _sapp.keycodes[0x00E] = SAPP_KEYCODE_BACKSPACE;
  3912. _sapp.keycodes[0x153] = SAPP_KEYCODE_DELETE;
  3913. _sapp.keycodes[0x14F] = SAPP_KEYCODE_END;
  3914. _sapp.keycodes[0x01C] = SAPP_KEYCODE_ENTER;
  3915. _sapp.keycodes[0x001] = SAPP_KEYCODE_ESCAPE;
  3916. _sapp.keycodes[0x147] = SAPP_KEYCODE_HOME;
  3917. _sapp.keycodes[0x152] = SAPP_KEYCODE_INSERT;
  3918. _sapp.keycodes[0x15D] = SAPP_KEYCODE_MENU;
  3919. _sapp.keycodes[0x151] = SAPP_KEYCODE_PAGE_DOWN;
  3920. _sapp.keycodes[0x149] = SAPP_KEYCODE_PAGE_UP;
  3921. _sapp.keycodes[0x045] = SAPP_KEYCODE_PAUSE;
  3922. _sapp.keycodes[0x146] = SAPP_KEYCODE_PAUSE;
  3923. _sapp.keycodes[0x039] = SAPP_KEYCODE_SPACE;
  3924. _sapp.keycodes[0x00F] = SAPP_KEYCODE_TAB;
  3925. _sapp.keycodes[0x03A] = SAPP_KEYCODE_CAPS_LOCK;
  3926. _sapp.keycodes[0x145] = SAPP_KEYCODE_NUM_LOCK;
  3927. _sapp.keycodes[0x046] = SAPP_KEYCODE_SCROLL_LOCK;
  3928. _sapp.keycodes[0x03B] = SAPP_KEYCODE_F1;
  3929. _sapp.keycodes[0x03C] = SAPP_KEYCODE_F2;
  3930. _sapp.keycodes[0x03D] = SAPP_KEYCODE_F3;
  3931. _sapp.keycodes[0x03E] = SAPP_KEYCODE_F4;
  3932. _sapp.keycodes[0x03F] = SAPP_KEYCODE_F5;
  3933. _sapp.keycodes[0x040] = SAPP_KEYCODE_F6;
  3934. _sapp.keycodes[0x041] = SAPP_KEYCODE_F7;
  3935. _sapp.keycodes[0x042] = SAPP_KEYCODE_F8;
  3936. _sapp.keycodes[0x043] = SAPP_KEYCODE_F9;
  3937. _sapp.keycodes[0x044] = SAPP_KEYCODE_F10;
  3938. _sapp.keycodes[0x057] = SAPP_KEYCODE_F11;
  3939. _sapp.keycodes[0x058] = SAPP_KEYCODE_F12;
  3940. _sapp.keycodes[0x064] = SAPP_KEYCODE_F13;
  3941. _sapp.keycodes[0x065] = SAPP_KEYCODE_F14;
  3942. _sapp.keycodes[0x066] = SAPP_KEYCODE_F15;
  3943. _sapp.keycodes[0x067] = SAPP_KEYCODE_F16;
  3944. _sapp.keycodes[0x068] = SAPP_KEYCODE_F17;
  3945. _sapp.keycodes[0x069] = SAPP_KEYCODE_F18;
  3946. _sapp.keycodes[0x06A] = SAPP_KEYCODE_F19;
  3947. _sapp.keycodes[0x06B] = SAPP_KEYCODE_F20;
  3948. _sapp.keycodes[0x06C] = SAPP_KEYCODE_F21;
  3949. _sapp.keycodes[0x06D] = SAPP_KEYCODE_F22;
  3950. _sapp.keycodes[0x06E] = SAPP_KEYCODE_F23;
  3951. _sapp.keycodes[0x076] = SAPP_KEYCODE_F24;
  3952. _sapp.keycodes[0x038] = SAPP_KEYCODE_LEFT_ALT;
  3953. _sapp.keycodes[0x01D] = SAPP_KEYCODE_LEFT_CONTROL;
  3954. _sapp.keycodes[0x02A] = SAPP_KEYCODE_LEFT_SHIFT;
  3955. _sapp.keycodes[0x15B] = SAPP_KEYCODE_LEFT_SUPER;
  3956. _sapp.keycodes[0x137] = SAPP_KEYCODE_PRINT_SCREEN;
  3957. _sapp.keycodes[0x138] = SAPP_KEYCODE_RIGHT_ALT;
  3958. _sapp.keycodes[0x11D] = SAPP_KEYCODE_RIGHT_CONTROL;
  3959. _sapp.keycodes[0x036] = SAPP_KEYCODE_RIGHT_SHIFT;
  3960. _sapp.keycodes[0x15C] = SAPP_KEYCODE_RIGHT_SUPER;
  3961. _sapp.keycodes[0x150] = SAPP_KEYCODE_DOWN;
  3962. _sapp.keycodes[0x14B] = SAPP_KEYCODE_LEFT;
  3963. _sapp.keycodes[0x14D] = SAPP_KEYCODE_RIGHT;
  3964. _sapp.keycodes[0x148] = SAPP_KEYCODE_UP;
  3965. _sapp.keycodes[0x052] = SAPP_KEYCODE_KP_0;
  3966. _sapp.keycodes[0x04F] = SAPP_KEYCODE_KP_1;
  3967. _sapp.keycodes[0x050] = SAPP_KEYCODE_KP_2;
  3968. _sapp.keycodes[0x051] = SAPP_KEYCODE_KP_3;
  3969. _sapp.keycodes[0x04B] = SAPP_KEYCODE_KP_4;
  3970. _sapp.keycodes[0x04C] = SAPP_KEYCODE_KP_5;
  3971. _sapp.keycodes[0x04D] = SAPP_KEYCODE_KP_6;
  3972. _sapp.keycodes[0x047] = SAPP_KEYCODE_KP_7;
  3973. _sapp.keycodes[0x048] = SAPP_KEYCODE_KP_8;
  3974. _sapp.keycodes[0x049] = SAPP_KEYCODE_KP_9;
  3975. _sapp.keycodes[0x04E] = SAPP_KEYCODE_KP_ADD;
  3976. _sapp.keycodes[0x053] = SAPP_KEYCODE_KP_DECIMAL;
  3977. _sapp.keycodes[0x135] = SAPP_KEYCODE_KP_DIVIDE;
  3978. _sapp.keycodes[0x11C] = SAPP_KEYCODE_KP_ENTER;
  3979. _sapp.keycodes[0x037] = SAPP_KEYCODE_KP_MULTIPLY;
  3980. _sapp.keycodes[0x04A] = SAPP_KEYCODE_KP_SUBTRACT;
  3981. }
  3982. /* updates current window and framebuffer size from the window's client rect, returns true if size has changed */
  3983. _SOKOL_PRIVATE bool _sapp_win32_update_dimensions(void) {
  3984. RECT rect;
  3985. if (GetClientRect(_sapp_win32_hwnd, &rect)) {
  3986. _sapp.window_width = (int)((float)(rect.right - rect.left) / _sapp_win32_window_scale);
  3987. _sapp.window_height = (int)((float)(rect.bottom - rect.top) / _sapp_win32_window_scale);
  3988. const int fb_width = (int)((float)_sapp.window_width * _sapp_win32_content_scale);
  3989. const int fb_height = (int)((float)_sapp.window_height * _sapp_win32_content_scale);
  3990. if ((fb_width != _sapp.framebuffer_width) || (fb_height != _sapp.framebuffer_height)) {
  3991. _sapp.framebuffer_width = (int)((float)_sapp.window_width * _sapp_win32_content_scale);
  3992. _sapp.framebuffer_height = (int)((float)_sapp.window_height * _sapp_win32_content_scale);
  3993. /* prevent a framebuffer size of 0 when window is minimized */
  3994. if (_sapp.framebuffer_width == 0) {
  3995. _sapp.framebuffer_width = 1;
  3996. }
  3997. if (_sapp.framebuffer_height == 0) {
  3998. _sapp.framebuffer_height = 1;
  3999. }
  4000. return true;
  4001. }
  4002. }
  4003. else {
  4004. _sapp.window_width = _sapp.window_height = 1;
  4005. _sapp.framebuffer_width = _sapp.framebuffer_height = 1;
  4006. }
  4007. return false;
  4008. }
  4009. _SOKOL_PRIVATE uint32_t _sapp_win32_mods(void) {
  4010. uint32_t mods = 0;
  4011. if (GetKeyState(VK_SHIFT) & (1<<15)) {
  4012. mods |= SAPP_MODIFIER_SHIFT;
  4013. }
  4014. if (GetKeyState(VK_CONTROL) & (1<<15)) {
  4015. mods |= SAPP_MODIFIER_CTRL;
  4016. }
  4017. if (GetKeyState(VK_MENU) & (1<<15)) {
  4018. mods |= SAPP_MODIFIER_ALT;
  4019. }
  4020. if ((GetKeyState(VK_LWIN) | GetKeyState(VK_RWIN)) & (1<<15)) {
  4021. mods |= SAPP_MODIFIER_SUPER;
  4022. }
  4023. return mods;
  4024. }
  4025. _SOKOL_PRIVATE void _sapp_win32_mouse_event(sapp_event_type type, sapp_mousebutton btn) {
  4026. if (_sapp_events_enabled()) {
  4027. _sapp_init_event(type);
  4028. _sapp.event.modifiers = _sapp_win32_mods();
  4029. _sapp.event.mouse_button = btn;
  4030. _sapp.event.mouse_x = _sapp.mouse_x;
  4031. _sapp.event.mouse_y = _sapp.mouse_y;
  4032. _sapp_call_event(&_sapp.event);
  4033. }
  4034. }
  4035. _SOKOL_PRIVATE void _sapp_win32_scroll_event(float x, float y) {
  4036. if (_sapp_events_enabled()) {
  4037. _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL);
  4038. _sapp.event.modifiers = _sapp_win32_mods();
  4039. _sapp.event.scroll_x = -x / 30.0f;
  4040. _sapp.event.scroll_y = y / 30.0f;
  4041. _sapp_call_event(&_sapp.event);
  4042. }
  4043. }
  4044. _SOKOL_PRIVATE void _sapp_win32_key_event(sapp_event_type type, int vk, bool repeat) {
  4045. if (_sapp_events_enabled() && (vk < SAPP_MAX_KEYCODES)) {
  4046. _sapp_init_event(type);
  4047. _sapp.event.modifiers = _sapp_win32_mods();
  4048. _sapp.event.key_code = _sapp.keycodes[vk];
  4049. _sapp.event.key_repeat = repeat;
  4050. _sapp_call_event(&_sapp.event);
  4051. /* check if a CLIPBOARD_PASTED event must be sent too */
  4052. if (_sapp.clipboard_enabled &&
  4053. (type == SAPP_EVENTTYPE_KEY_DOWN) &&
  4054. (_sapp.event.modifiers == SAPP_MODIFIER_CTRL) &&
  4055. (_sapp.event.key_code == SAPP_KEYCODE_V))
  4056. {
  4057. _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED);
  4058. _sapp_call_event(&_sapp.event);
  4059. }
  4060. }
  4061. }
  4062. _SOKOL_PRIVATE void _sapp_win32_char_event(uint32_t c, bool repeat) {
  4063. if (_sapp_events_enabled() && (c >= 32)) {
  4064. _sapp_init_event(SAPP_EVENTTYPE_CHAR);
  4065. _sapp.event.modifiers = _sapp_win32_mods();
  4066. _sapp.event.char_code = c;
  4067. _sapp.event.key_repeat = repeat;
  4068. _sapp_call_event(&_sapp.event);
  4069. }
  4070. }
  4071. _SOKOL_PRIVATE void _sapp_win32_app_event(sapp_event_type type) {
  4072. if (_sapp_events_enabled()) {
  4073. _sapp_init_event(type);
  4074. _sapp_call_event(&_sapp.event);
  4075. }
  4076. }
  4077. _SOKOL_PRIVATE LRESULT CALLBACK _sapp_win32_wndproc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  4078. /* FIXME: refresh rendering during resize with a WM_TIMER event */
  4079. if (!_sapp_win32_in_create_window) {
  4080. switch (uMsg) {
  4081. case WM_CLOSE:
  4082. /* only give user a chance to intervene when sapp_quit() wasn't already called */
  4083. if (!_sapp.quit_ordered) {
  4084. /* if window should be closed and event handling is enabled, give user code
  4085. a change to intervene via sapp_cancel_quit()
  4086. */
  4087. _sapp.quit_requested = true;
  4088. _sapp_win32_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED);
  4089. /* if user code hasn't intervened, quit the app */
  4090. if (_sapp.quit_requested) {
  4091. _sapp.quit_ordered = true;
  4092. }
  4093. }
  4094. if (_sapp.quit_ordered) {
  4095. PostQuitMessage(0);
  4096. }
  4097. return 0;
  4098. case WM_SYSCOMMAND:
  4099. switch (wParam & 0xFFF0) {
  4100. case SC_SCREENSAVE:
  4101. case SC_MONITORPOWER:
  4102. if (_sapp.desc.fullscreen) {
  4103. /* disable screen saver and blanking in fullscreen mode */
  4104. return 0;
  4105. }
  4106. break;
  4107. case SC_KEYMENU:
  4108. /* user trying to access menu via ALT */
  4109. return 0;
  4110. }
  4111. break;
  4112. case WM_ERASEBKGND:
  4113. return 1;
  4114. case WM_SIZE:
  4115. {
  4116. const bool iconified = wParam == SIZE_MINIMIZED;
  4117. if (iconified != _sapp_win32_iconified) {
  4118. _sapp_win32_iconified = iconified;
  4119. if (iconified) {
  4120. _sapp_win32_app_event(SAPP_EVENTTYPE_ICONIFIED);
  4121. }
  4122. else {
  4123. _sapp_win32_app_event(SAPP_EVENTTYPE_RESTORED);
  4124. }
  4125. }
  4126. }
  4127. break;
  4128. case WM_SETCURSOR:
  4129. if (_sapp.desc.user_cursor) {
  4130. if (LOWORD(lParam) == HTCLIENT) {
  4131. _sapp_win32_app_event(SAPP_EVENTTYPE_UPDATE_CURSOR);
  4132. return 1;
  4133. }
  4134. }
  4135. break;
  4136. case WM_LBUTTONDOWN:
  4137. _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_LEFT);
  4138. break;
  4139. case WM_RBUTTONDOWN:
  4140. _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_RIGHT);
  4141. break;
  4142. case WM_MBUTTONDOWN:
  4143. _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, SAPP_MOUSEBUTTON_MIDDLE);
  4144. break;
  4145. case WM_LBUTTONUP:
  4146. _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_LEFT);
  4147. break;
  4148. case WM_RBUTTONUP:
  4149. _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_RIGHT);
  4150. break;
  4151. case WM_MBUTTONUP:
  4152. _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, SAPP_MOUSEBUTTON_MIDDLE);
  4153. break;
  4154. case WM_MOUSEMOVE:
  4155. _sapp.mouse_x = (float)GET_X_LPARAM(lParam) * _sapp_win32_mouse_scale;
  4156. _sapp.mouse_y = (float)GET_Y_LPARAM(lParam) * _sapp_win32_mouse_scale;
  4157. if (!_sapp.win32_mouse_tracked) {
  4158. _sapp.win32_mouse_tracked = true;
  4159. TRACKMOUSEEVENT tme;
  4160. memset(&tme, 0, sizeof(tme));
  4161. tme.cbSize = sizeof(tme);
  4162. tme.dwFlags = TME_LEAVE;
  4163. tme.hwndTrack = _sapp_win32_hwnd;
  4164. TrackMouseEvent(&tme);
  4165. _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID);
  4166. }
  4167. _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID);
  4168. break;
  4169. case WM_MOUSELEAVE:
  4170. _sapp.win32_mouse_tracked = false;
  4171. _sapp_win32_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID);
  4172. break;
  4173. case WM_MOUSEWHEEL:
  4174. _sapp_win32_scroll_event(0.0f, (float)((SHORT)HIWORD(wParam)));
  4175. break;
  4176. case WM_MOUSEHWHEEL:
  4177. _sapp_win32_scroll_event((float)((SHORT)HIWORD(wParam)), 0.0f);
  4178. break;
  4179. case WM_CHAR:
  4180. _sapp_win32_char_event((uint32_t)wParam, !!(lParam&0x40000000));
  4181. break;
  4182. case WM_KEYDOWN:
  4183. case WM_SYSKEYDOWN:
  4184. _sapp_win32_key_event(SAPP_EVENTTYPE_KEY_DOWN, (int)(HIWORD(lParam)&0x1FF), !!(lParam&0x40000000));
  4185. break;
  4186. case WM_KEYUP:
  4187. case WM_SYSKEYUP:
  4188. _sapp_win32_key_event(SAPP_EVENTTYPE_KEY_UP, (int)(HIWORD(lParam)&0x1FF), false);
  4189. break;
  4190. default:
  4191. break;
  4192. }
  4193. }
  4194. return DefWindowProcW(hWnd, uMsg, wParam, lParam);
  4195. }
  4196. _SOKOL_PRIVATE void _sapp_win32_create_window(void) {
  4197. WNDCLASSW wndclassw;
  4198. memset(&wndclassw, 0, sizeof(wndclassw));
  4199. wndclassw.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
  4200. wndclassw.lpfnWndProc = (WNDPROC) _sapp_win32_wndproc;
  4201. wndclassw.hInstance = GetModuleHandleW(NULL);
  4202. wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW);
  4203. wndclassw.hIcon = LoadIcon(NULL, IDI_WINLOGO);
  4204. wndclassw.lpszClassName = L"SOKOLAPP";
  4205. RegisterClassW(&wndclassw);
  4206. DWORD win_style;
  4207. const DWORD win_ex_style = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
  4208. RECT rect = { 0, 0, 0, 0 };
  4209. if (_sapp.desc.fullscreen) {
  4210. win_style = WS_POPUP | WS_SYSMENU | WS_VISIBLE;
  4211. rect.right = GetSystemMetrics(SM_CXSCREEN);
  4212. rect.bottom = GetSystemMetrics(SM_CYSCREEN);
  4213. }
  4214. else {
  4215. win_style = WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX;
  4216. rect.right = (int) ((float)_sapp.window_width * _sapp_win32_window_scale);
  4217. rect.bottom = (int) ((float)_sapp.window_height * _sapp_win32_window_scale);
  4218. }
  4219. AdjustWindowRectEx(&rect, win_style, FALSE, win_ex_style);
  4220. const int win_width = rect.right - rect.left;
  4221. const int win_height = rect.bottom - rect.top;
  4222. _sapp_win32_in_create_window = true;
  4223. _sapp_win32_hwnd = CreateWindowExW(
  4224. win_ex_style, /* dwExStyle */
  4225. L"SOKOLAPP", /* lpClassName */
  4226. _sapp.window_title_wide, /* lpWindowName */
  4227. win_style, /* dwStyle */
  4228. CW_USEDEFAULT, /* X */
  4229. CW_USEDEFAULT, /* Y */
  4230. win_width, /* nWidth */
  4231. win_height, /* nHeight */
  4232. NULL, /* hWndParent */
  4233. NULL, /* hMenu */
  4234. GetModuleHandle(NULL), /* hInstance */
  4235. NULL); /* lParam */
  4236. ShowWindow(_sapp_win32_hwnd, SW_SHOW);
  4237. _sapp_win32_in_create_window = false;
  4238. _sapp_win32_dc = GetDC(_sapp_win32_hwnd);
  4239. SOKOL_ASSERT(_sapp_win32_dc);
  4240. _sapp_win32_update_dimensions();
  4241. }
  4242. _SOKOL_PRIVATE void _sapp_win32_destroy_window(void) {
  4243. DestroyWindow(_sapp_win32_hwnd); _sapp_win32_hwnd = 0;
  4244. UnregisterClassW(L"SOKOLAPP", GetModuleHandleW(NULL));
  4245. }
  4246. _SOKOL_PRIVATE void _sapp_win32_init_dpi(void) {
  4247. SOKOL_ASSERT(0 == _sapp_win32_setprocessdpiaware);
  4248. SOKOL_ASSERT(0 == _sapp_win32_setprocessdpiawareness);
  4249. SOKOL_ASSERT(0 == _sapp_win32_getdpiformonitor);
  4250. HINSTANCE user32 = LoadLibraryA("user32.dll");
  4251. if (user32) {
  4252. _sapp_win32_setprocessdpiaware = (SETPROCESSDPIAWARE_T) GetProcAddress(user32, "SetProcessDPIAware");
  4253. }
  4254. HINSTANCE shcore = LoadLibraryA("shcore.dll");
  4255. if (shcore) {
  4256. _sapp_win32_setprocessdpiawareness = (SETPROCESSDPIAWARENESS_T) GetProcAddress(shcore, "SetProcessDpiAwareness");
  4257. _sapp_win32_getdpiformonitor = (GETDPIFORMONITOR_T) GetProcAddress(shcore, "GetDpiForMonitor");
  4258. }
  4259. if (_sapp_win32_setprocessdpiawareness) {
  4260. /* if the app didn't request HighDPI rendering, let Windows do the upscaling */
  4261. PROCESS_DPI_AWARENESS process_dpi_awareness = PROCESS_SYSTEM_DPI_AWARE;
  4262. _sapp_win32_dpi_aware = true;
  4263. if (!_sapp.desc.high_dpi) {
  4264. process_dpi_awareness = PROCESS_DPI_UNAWARE;
  4265. _sapp_win32_dpi_aware = false;
  4266. }
  4267. _sapp_win32_setprocessdpiawareness(process_dpi_awareness);
  4268. }
  4269. else if (_sapp_win32_setprocessdpiaware) {
  4270. _sapp_win32_setprocessdpiaware();
  4271. _sapp_win32_dpi_aware = true;
  4272. }
  4273. /* get dpi scale factor for main monitor */
  4274. if (_sapp_win32_getdpiformonitor && _sapp_win32_dpi_aware) {
  4275. POINT pt = { 1, 1 };
  4276. HMONITOR hm = MonitorFromPoint(pt, MONITOR_DEFAULTTONEAREST);
  4277. UINT dpix, dpiy;
  4278. HRESULT hr = _sapp_win32_getdpiformonitor(hm, MDT_EFFECTIVE_DPI, &dpix, &dpiy);
  4279. _SOKOL_UNUSED(hr);
  4280. SOKOL_ASSERT(SUCCEEDED(hr));
  4281. /* clamp window scale to an integer factor */
  4282. _sapp_win32_window_scale = (float)dpix / 96.0f;
  4283. }
  4284. else {
  4285. _sapp_win32_window_scale = 1.0f;
  4286. }
  4287. if (_sapp.desc.high_dpi) {
  4288. _sapp_win32_content_scale = _sapp_win32_window_scale;
  4289. _sapp_win32_mouse_scale = 1.0f;
  4290. }
  4291. else {
  4292. _sapp_win32_content_scale = 1.0f;
  4293. _sapp_win32_mouse_scale = 1.0f / _sapp_win32_window_scale;
  4294. }
  4295. _sapp.dpi_scale = _sapp_win32_content_scale;
  4296. if (user32) {
  4297. FreeLibrary(user32);
  4298. }
  4299. if (shcore) {
  4300. FreeLibrary(shcore);
  4301. }
  4302. }
  4303. _SOKOL_PRIVATE bool _sapp_win32_set_clipboard_string(const char* str) {
  4304. SOKOL_ASSERT(str);
  4305. SOKOL_ASSERT(_sapp_win32_hwnd);
  4306. SOKOL_ASSERT(_sapp.clipboard_enabled && (_sapp.clipboard_size > 0));
  4307. wchar_t* wchar_buf = 0;
  4308. const int wchar_buf_size = _sapp.clipboard_size * sizeof(wchar_t);
  4309. HANDLE object = GlobalAlloc(GMEM_MOVEABLE, wchar_buf_size);
  4310. if (!object) {
  4311. goto error;
  4312. }
  4313. wchar_buf = (wchar_t*) GlobalLock(object);
  4314. if (!wchar_buf) {
  4315. goto error;
  4316. }
  4317. if (!_sapp_win32_utf8_to_wide(str, wchar_buf, wchar_buf_size)) {
  4318. goto error;
  4319. }
  4320. GlobalUnlock(wchar_buf);
  4321. wchar_buf = 0;
  4322. if (!OpenClipboard(_sapp_win32_hwnd)) {
  4323. goto error;
  4324. }
  4325. EmptyClipboard();
  4326. SetClipboardData(CF_UNICODETEXT, object);
  4327. CloseClipboard();
  4328. return true;
  4329. error:
  4330. if (wchar_buf) {
  4331. GlobalUnlock(object);
  4332. }
  4333. if (object) {
  4334. GlobalFree(object);
  4335. }
  4336. return false;
  4337. }
  4338. _SOKOL_PRIVATE const char* _sapp_win32_get_clipboard_string(void) {
  4339. SOKOL_ASSERT(_sapp.clipboard_enabled && _sapp.clipboard);
  4340. SOKOL_ASSERT(_sapp_win32_hwnd);
  4341. if (!OpenClipboard(_sapp_win32_hwnd)) {
  4342. /* silently ignore any errors and just return the current
  4343. content of the local clipboard buffer
  4344. */
  4345. return _sapp.clipboard;
  4346. }
  4347. HANDLE object = GetClipboardData(CF_UNICODETEXT);
  4348. if (!object) {
  4349. CloseClipboard();
  4350. return _sapp.clipboard;
  4351. }
  4352. const wchar_t* wchar_buf = (const wchar_t*) GlobalLock(object);
  4353. if (!wchar_buf) {
  4354. CloseClipboard();
  4355. return _sapp.clipboard;
  4356. }
  4357. _sapp_win32_wide_to_utf8(wchar_buf, _sapp.clipboard, _sapp.clipboard_size);
  4358. GlobalUnlock(object);
  4359. CloseClipboard();
  4360. return _sapp.clipboard;
  4361. }
  4362. _SOKOL_PRIVATE void _sapp_run(const sapp_desc* desc) {
  4363. _sapp_init_state(desc);
  4364. _sapp_win32_init_keytable();
  4365. _sapp_win32_utf8_to_wide(_sapp.window_title, _sapp.window_title_wide, sizeof(_sapp.window_title_wide));
  4366. _sapp_win32_init_dpi();
  4367. _sapp_win32_create_window();
  4368. #if defined(SOKOL_D3D11)
  4369. _sapp_d3d11_create_device_and_swapchain();
  4370. _sapp_d3d11_create_default_render_target();
  4371. #endif
  4372. #if defined(SOKOL_GLCORE33)
  4373. _sapp_wgl_init();
  4374. _sapp_wgl_load_extensions();
  4375. _sapp_wgl_create_context();
  4376. #if !defined(SOKOL_WIN32_NO_GL_LOADER)
  4377. _sapp_win32_gl_loadfuncs();
  4378. #endif
  4379. #endif
  4380. _sapp.valid = true;
  4381. bool done = false;
  4382. while (!(done || _sapp.quit_ordered)) {
  4383. MSG msg;
  4384. while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE)) {
  4385. if (WM_QUIT == msg.message) {
  4386. done = true;
  4387. continue;
  4388. }
  4389. else {
  4390. TranslateMessage(&msg);
  4391. DispatchMessage(&msg);
  4392. }
  4393. }
  4394. _sapp_frame();
  4395. #if defined(SOKOL_D3D11)
  4396. IDXGISwapChain_Present(_sapp_dxgi_swap_chain, _sapp.swap_interval, 0);
  4397. if (IsIconic(_sapp_win32_hwnd)) {
  4398. Sleep(16 * _sapp.swap_interval);
  4399. }
  4400. #endif
  4401. #if defined(SOKOL_GLCORE33)
  4402. _sapp_wgl_swap_buffers();
  4403. #endif
  4404. /* check for window resized, this cannot happen in WM_SIZE as it explodes memory usage */
  4405. if (_sapp_win32_update_dimensions()) {
  4406. #if defined(SOKOL_D3D11)
  4407. _sapp_d3d11_resize_default_render_target();
  4408. #endif
  4409. _sapp_win32_app_event(SAPP_EVENTTYPE_RESIZED);
  4410. }
  4411. if (_sapp.quit_requested) {
  4412. PostMessage(_sapp_win32_hwnd, WM_CLOSE, 0, 0);
  4413. }
  4414. }
  4415. _sapp_call_cleanup();
  4416. #if defined(SOKOL_D3D11)
  4417. _sapp_d3d11_destroy_default_render_target();
  4418. _sapp_d3d11_destroy_device_and_swapchain();
  4419. #else
  4420. _sapp_wgl_destroy_context();
  4421. _sapp_wgl_shutdown();
  4422. #endif
  4423. _sapp_win32_destroy_window();
  4424. _sapp_discard_state();
  4425. }
  4426. static char** _sapp_win32_command_line_to_utf8_argv(LPWSTR w_command_line, int* o_argc) {
  4427. int argc = 0;
  4428. char** argv = 0;
  4429. char* args;
  4430. LPWSTR* w_argv = CommandLineToArgvW(w_command_line, &argc);
  4431. if (w_argv == NULL) {
  4432. _sapp_fail("Win32: failed to parse command line");
  4433. } else {
  4434. size_t size = wcslen(w_command_line) * 4;
  4435. argv = (char**) SOKOL_CALLOC(1, (argc + 1) * sizeof(char*) + size);
  4436. args = (char*)&argv[argc + 1];
  4437. int n;
  4438. for (int i = 0; i < argc; ++i) {
  4439. n = WideCharToMultiByte(CP_UTF8, 0, w_argv[i], -1, args, (int)size, NULL, NULL);
  4440. if (n == 0) {
  4441. _sapp_fail("Win32: failed to convert all arguments to utf8");
  4442. break;
  4443. }
  4444. argv[i] = args;
  4445. size -= n;
  4446. args += n;
  4447. }
  4448. LocalFree(w_argv);
  4449. }
  4450. *o_argc = argc;
  4451. return argv;
  4452. }
  4453. #if !defined(SOKOL_NO_ENTRY)
  4454. #if defined(SOKOL_WIN32_FORCE_MAIN)
  4455. int main(int argc, char* argv[]) {
  4456. sapp_desc desc = sokol_main(argc, argv);
  4457. _sapp_run(&desc);
  4458. return 0;
  4459. }
  4460. #else
  4461. int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) {
  4462. _SOKOL_UNUSED(hInstance);
  4463. _SOKOL_UNUSED(hPrevInstance);
  4464. _SOKOL_UNUSED(lpCmdLine);
  4465. _SOKOL_UNUSED(nCmdShow);
  4466. int argc_utf8 = 0;
  4467. char** argv_utf8 = _sapp_win32_command_line_to_utf8_argv(GetCommandLineW(), &argc_utf8);
  4468. sapp_desc desc = sokol_main(argc_utf8, argv_utf8);
  4469. _sapp_run(&desc);
  4470. SOKOL_FREE(argv_utf8);
  4471. return 0;
  4472. }
  4473. #endif /* SOKOL_WIN32_FORCE_MAIN */
  4474. #endif /* SOKOL_NO_ENTRY */
  4475. #undef _SAPP_SAFE_RELEASE
  4476. #endif /* WINDOWS */
  4477. /*== Android ================================================================*/
  4478. #if defined(__ANDROID__)
  4479. #include <pthread.h>
  4480. #include <unistd.h>
  4481. #include <android/native_activity.h>
  4482. #include <android/looper.h>
  4483. #include <EGL/egl.h>
  4484. #if defined(SOKOL_GLES3)
  4485. #include <GLES3/gl3.h>
  4486. #else
  4487. #ifndef GL_EXT_PROTOTYPES
  4488. #define GL_GLEXT_PROTOTYPES
  4489. #endif
  4490. #include <GLES2/gl2.h>
  4491. #include <GLES2/gl2ext.h>
  4492. #endif
  4493. typedef struct {
  4494. pthread_t thread;
  4495. pthread_mutex_t mutex;
  4496. pthread_cond_t cond;
  4497. int read_from_main_fd;
  4498. int write_from_main_fd;
  4499. } _sapp_android_pt_t;
  4500. typedef struct {
  4501. ANativeWindow* window;
  4502. AInputQueue* input;
  4503. } _sapp_android_resources_t;
  4504. typedef enum {
  4505. _SOKOL_ANDROID_MSG_CREATE,
  4506. _SOKOL_ANDROID_MSG_RESUME,
  4507. _SOKOL_ANDROID_MSG_PAUSE,
  4508. _SOKOL_ANDROID_MSG_FOCUS,
  4509. _SOKOL_ANDROID_MSG_NO_FOCUS,
  4510. _SOKOL_ANDROID_MSG_SET_NATIVE_WINDOW,
  4511. _SOKOL_ANDROID_MSG_SET_INPUT_QUEUE,
  4512. _SOKOL_ANDROID_MSG_DESTROY,
  4513. } _sapp_android_msg_t;
  4514. typedef struct {
  4515. ANativeActivity* activity;
  4516. _sapp_android_pt_t pt;
  4517. _sapp_android_resources_t pending;
  4518. _sapp_android_resources_t current;
  4519. ALooper* looper;
  4520. bool is_thread_started;
  4521. bool is_thread_stopping;
  4522. bool is_thread_stopped;
  4523. bool has_created;
  4524. bool has_resumed;
  4525. bool has_focus;
  4526. EGLConfig config;
  4527. EGLDisplay display;
  4528. EGLContext context;
  4529. EGLSurface surface;
  4530. } _sapp_android_state_t;
  4531. static _sapp_android_state_t _sapp_android_state;
  4532. /* android loop thread */
  4533. _SOKOL_PRIVATE bool _sapp_android_init_egl(void) {
  4534. _sapp_android_state_t* state = &_sapp_android_state;
  4535. SOKOL_ASSERT(state->display == EGL_NO_DISPLAY);
  4536. SOKOL_ASSERT(state->context == EGL_NO_CONTEXT);
  4537. EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
  4538. if (display == EGL_NO_DISPLAY) {
  4539. return false;
  4540. }
  4541. if (eglInitialize(display, NULL, NULL) == EGL_FALSE) {
  4542. return false;
  4543. }
  4544. EGLint alpha_size = _sapp.desc.alpha ? 8 : 0;
  4545. const EGLint cfg_attributes[] = {
  4546. EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
  4547. EGL_RED_SIZE, 8,
  4548. EGL_GREEN_SIZE, 8,
  4549. EGL_BLUE_SIZE, 8,
  4550. EGL_ALPHA_SIZE, alpha_size,
  4551. EGL_DEPTH_SIZE, 16,
  4552. EGL_STENCIL_SIZE, 0,
  4553. EGL_NONE,
  4554. };
  4555. EGLConfig available_cfgs[32];
  4556. EGLint cfg_count;
  4557. eglChooseConfig(display, cfg_attributes, available_cfgs, 32, &cfg_count);
  4558. SOKOL_ASSERT(cfg_count > 0);
  4559. SOKOL_ASSERT(cfg_count <= 32);
  4560. /* find config with 8-bit rgb buffer if available, ndk sample does not trust egl spec */
  4561. EGLConfig config;
  4562. bool exact_cfg_found = false;
  4563. for (int i = 0; i < cfg_count; ++i) {
  4564. EGLConfig c = available_cfgs[i];
  4565. EGLint r, g, b, a, d;
  4566. if (eglGetConfigAttrib(display, c, EGL_RED_SIZE, &r) == EGL_TRUE &&
  4567. eglGetConfigAttrib(display, c, EGL_GREEN_SIZE, &g) == EGL_TRUE &&
  4568. eglGetConfigAttrib(display, c, EGL_BLUE_SIZE, &b) == EGL_TRUE &&
  4569. eglGetConfigAttrib(display, c, EGL_ALPHA_SIZE, &a) == EGL_TRUE &&
  4570. eglGetConfigAttrib(display, c, EGL_DEPTH_SIZE, &d) == EGL_TRUE &&
  4571. r == 8 && g == 8 && b == 8 && (alpha_size == 0 || a == alpha_size) && d == 16) {
  4572. exact_cfg_found = true;
  4573. config = c;
  4574. break;
  4575. }
  4576. }
  4577. if (!exact_cfg_found) {
  4578. config = available_cfgs[0];
  4579. }
  4580. EGLint ctx_attributes[] = {
  4581. #if defined(SOKOL_GLES3)
  4582. EGL_CONTEXT_CLIENT_VERSION, _sapp.desc.gl_force_gles2 ? 2 : 3,
  4583. #else
  4584. EGL_CONTEXT_CLIENT_VERSION, 2,
  4585. #endif
  4586. EGL_NONE,
  4587. };
  4588. EGLContext context = eglCreateContext(display, config, EGL_NO_CONTEXT, ctx_attributes);
  4589. if (context == EGL_NO_CONTEXT) {
  4590. return false;
  4591. }
  4592. state->config = config;
  4593. state->display = display;
  4594. state->context = context;
  4595. return true;
  4596. }
  4597. _SOKOL_PRIVATE void _sapp_android_cleanup_egl(void) {
  4598. _sapp_android_state_t* state = &_sapp_android_state;
  4599. if (state->display != EGL_NO_DISPLAY) {
  4600. eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  4601. if (state->surface != EGL_NO_SURFACE) {
  4602. SOKOL_LOG("Destroying egl surface");
  4603. eglDestroySurface(state->display, state->surface);
  4604. state->surface = EGL_NO_SURFACE;
  4605. }
  4606. if (state->context != EGL_NO_CONTEXT) {
  4607. SOKOL_LOG("Destroying egl context");
  4608. eglDestroyContext(state->display, state->context);
  4609. state->context = EGL_NO_CONTEXT;
  4610. }
  4611. SOKOL_LOG("Terminating egl display");
  4612. eglTerminate(state->display);
  4613. state->display = EGL_NO_DISPLAY;
  4614. }
  4615. }
  4616. _SOKOL_PRIVATE bool _sapp_android_init_egl_surface(ANativeWindow* window) {
  4617. _sapp_android_state_t* state = &_sapp_android_state;
  4618. SOKOL_ASSERT(state->display != EGL_NO_DISPLAY);
  4619. SOKOL_ASSERT(state->context != EGL_NO_CONTEXT);
  4620. SOKOL_ASSERT(state->surface == EGL_NO_SURFACE);
  4621. SOKOL_ASSERT(window);
  4622. /* TODO: set window flags */
  4623. /* ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_KEEP_SCREEN_ON, 0); */
  4624. /* create egl surface and make it current */
  4625. EGLSurface surface = eglCreateWindowSurface(state->display, state->config, window, NULL);
  4626. if (surface == EGL_NO_SURFACE) {
  4627. return false;
  4628. }
  4629. if (eglMakeCurrent(state->display, surface, surface, state->context) == EGL_FALSE) {
  4630. return false;
  4631. }
  4632. state->surface = surface;
  4633. return true;
  4634. }
  4635. _SOKOL_PRIVATE void _sapp_android_cleanup_egl_surface(void) {
  4636. _sapp_android_state_t* state = &_sapp_android_state;
  4637. if (state->display == EGL_NO_DISPLAY) {
  4638. return;
  4639. }
  4640. eglMakeCurrent(state->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
  4641. if (state->surface != EGL_NO_SURFACE) {
  4642. eglDestroySurface(state->display, state->surface);
  4643. state->surface = EGL_NO_SURFACE;
  4644. }
  4645. }
  4646. _SOKOL_PRIVATE void _sapp_android_app_event(sapp_event_type type) {
  4647. if (_sapp_events_enabled()) {
  4648. _sapp_init_event(type);
  4649. SOKOL_LOG("event_cb()");
  4650. _sapp_call_event(&_sapp.event);
  4651. }
  4652. }
  4653. _SOKOL_PRIVATE void _sapp_android_update_dimensions(ANativeWindow* window, bool force_update) {
  4654. _sapp_android_state_t* state = &_sapp_android_state;
  4655. SOKOL_ASSERT(state->display != EGL_NO_DISPLAY);
  4656. SOKOL_ASSERT(state->context != EGL_NO_CONTEXT);
  4657. SOKOL_ASSERT(state->surface != EGL_NO_SURFACE);
  4658. SOKOL_ASSERT(window);
  4659. const int32_t win_w = ANativeWindow_getWidth(window);
  4660. const int32_t win_h = ANativeWindow_getHeight(window);
  4661. SOKOL_ASSERT(win_w >= 0 && win_h >= 0);
  4662. const bool win_changed = (win_w != _sapp.window_width) || (win_h != _sapp.window_height);
  4663. _sapp.window_width = win_w;
  4664. _sapp.window_height = win_h;
  4665. if (win_changed || force_update) {
  4666. if (!_sapp.desc.high_dpi) {
  4667. const int32_t buf_w = win_w / 2;
  4668. const int32_t buf_h = win_h / 2;
  4669. EGLint format;
  4670. EGLBoolean egl_result = eglGetConfigAttrib(state->display, state->config, EGL_NATIVE_VISUAL_ID, &format);
  4671. SOKOL_ASSERT(egl_result == EGL_TRUE);
  4672. /* NOTE: calling ANativeWindow_setBuffersGeometry() with the same dimensions
  4673. as the ANativeWindow size results in weird display artefacts, that's
  4674. why it's only called when the buffer geometry is different from
  4675. the window size
  4676. */
  4677. int32_t result = ANativeWindow_setBuffersGeometry(window, buf_w, buf_h, format);
  4678. SOKOL_ASSERT(result == 0);
  4679. }
  4680. }
  4681. /* query surface size */
  4682. EGLint fb_w, fb_h;
  4683. EGLBoolean egl_result_w = eglQuerySurface(state->display, state->surface, EGL_WIDTH, &fb_w);
  4684. EGLBoolean egl_result_h = eglQuerySurface(state->display, state->surface, EGL_HEIGHT, &fb_h);
  4685. SOKOL_ASSERT(egl_result_w == EGL_TRUE);
  4686. SOKOL_ASSERT(egl_result_h == EGL_TRUE);
  4687. const bool fb_changed = (fb_w != _sapp.framebuffer_width) || (fb_h != _sapp.framebuffer_height);
  4688. _sapp.framebuffer_width = fb_w;
  4689. _sapp.framebuffer_height = fb_h;
  4690. _sapp.dpi_scale = (float)_sapp.framebuffer_width / (float)_sapp.window_width;
  4691. if (win_changed || fb_changed || force_update) {
  4692. if (!_sapp.first_frame) {
  4693. SOKOL_LOG("SAPP_EVENTTYPE_RESIZED");
  4694. _sapp_android_app_event(SAPP_EVENTTYPE_RESIZED);
  4695. }
  4696. }
  4697. }
  4698. _SOKOL_PRIVATE void _sapp_android_cleanup(void) {
  4699. _sapp_android_state_t* state = &_sapp_android_state;
  4700. SOKOL_LOG("Cleaning up");
  4701. if (state->surface != EGL_NO_SURFACE) {
  4702. /* egl context is bound, cleanup gracefully */
  4703. if (_sapp.init_called && !_sapp.cleanup_called) {
  4704. SOKOL_LOG("cleanup_cb()");
  4705. _sapp_call_cleanup();
  4706. }
  4707. }
  4708. /* always try to cleanup by destroying egl context */
  4709. _sapp_android_cleanup_egl();
  4710. }
  4711. _SOKOL_PRIVATE void _sapp_android_shutdown(void) {
  4712. /* try to cleanup while we still have a surface and can call cleanup_cb() */
  4713. _sapp_android_cleanup();
  4714. /* request exit */
  4715. ANativeActivity_finish(_sapp_android_state.activity);
  4716. }
  4717. _SOKOL_PRIVATE void _sapp_android_frame(void) {
  4718. _sapp_android_state_t* state = &_sapp_android_state;
  4719. SOKOL_ASSERT(state->display != EGL_NO_DISPLAY);
  4720. SOKOL_ASSERT(state->context != EGL_NO_CONTEXT);
  4721. SOKOL_ASSERT(state->surface != EGL_NO_SURFACE);
  4722. _sapp_android_update_dimensions(state->current.window, false);
  4723. _sapp_frame();
  4724. eglSwapBuffers(state->display, _sapp_android_state.surface);
  4725. }
  4726. _SOKOL_PRIVATE bool _sapp_android_touch_event(const AInputEvent* e) {
  4727. if (AInputEvent_getType(e) != AINPUT_EVENT_TYPE_MOTION) {
  4728. return false;
  4729. }
  4730. if (!_sapp_events_enabled()) {
  4731. return false;
  4732. }
  4733. int32_t action_idx = AMotionEvent_getAction(e);
  4734. int32_t action = action_idx & AMOTION_EVENT_ACTION_MASK;
  4735. sapp_event_type type = SAPP_EVENTTYPE_INVALID;
  4736. switch (action) {
  4737. case AMOTION_EVENT_ACTION_DOWN:
  4738. SOKOL_LOG("Touch: down");
  4739. case AMOTION_EVENT_ACTION_POINTER_DOWN:
  4740. SOKOL_LOG("Touch: ptr down");
  4741. type = SAPP_EVENTTYPE_TOUCHES_BEGAN;
  4742. break;
  4743. case AMOTION_EVENT_ACTION_MOVE:
  4744. type = SAPP_EVENTTYPE_TOUCHES_MOVED;
  4745. break;
  4746. case AMOTION_EVENT_ACTION_UP:
  4747. SOKOL_LOG("Touch: up");
  4748. case AMOTION_EVENT_ACTION_POINTER_UP:
  4749. SOKOL_LOG("Touch: ptr up");
  4750. type = SAPP_EVENTTYPE_TOUCHES_ENDED;
  4751. break;
  4752. case AMOTION_EVENT_ACTION_CANCEL:
  4753. SOKOL_LOG("Touch: cancel");
  4754. type = SAPP_EVENTTYPE_TOUCHES_CANCELLED;
  4755. break;
  4756. default:
  4757. break;
  4758. }
  4759. if (type == SAPP_EVENTTYPE_INVALID) {
  4760. return false;
  4761. }
  4762. int32_t idx = action_idx >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
  4763. _sapp_init_event(type);
  4764. _sapp.event.num_touches = AMotionEvent_getPointerCount(e);
  4765. if (_sapp.event.num_touches > SAPP_MAX_TOUCHPOINTS) {
  4766. _sapp.event.num_touches = SAPP_MAX_TOUCHPOINTS;
  4767. }
  4768. for (int32_t i = 0; i < _sapp.event.num_touches; i++) {
  4769. sapp_touchpoint* dst = &_sapp.event.touches[i];
  4770. dst->identifier = AMotionEvent_getPointerId(e, i);
  4771. dst->pos_x = (AMotionEvent_getRawX(e, i) / _sapp.window_width) * _sapp.framebuffer_width;
  4772. dst->pos_y = (AMotionEvent_getRawY(e, i) / _sapp.window_height) * _sapp.framebuffer_height;
  4773. if (action == AMOTION_EVENT_ACTION_POINTER_DOWN ||
  4774. action == AMOTION_EVENT_ACTION_POINTER_UP) {
  4775. dst->changed = i == idx;
  4776. } else {
  4777. dst->changed = true;
  4778. }
  4779. }
  4780. _sapp_call_event(&_sapp.event);
  4781. return true;
  4782. }
  4783. _SOKOL_PRIVATE bool _sapp_android_key_event(const AInputEvent* e) {
  4784. if (AInputEvent_getType(e) != AINPUT_EVENT_TYPE_KEY) {
  4785. return false;
  4786. }
  4787. if (AKeyEvent_getKeyCode(e) == AKEYCODE_BACK) {
  4788. /* FIXME: this should be hooked into a "really quit?" mechanism
  4789. so the app can ask the user for confirmation, this is currently
  4790. generally missing in sokol_app.h
  4791. */
  4792. _sapp_android_shutdown();
  4793. return true;
  4794. }
  4795. return false;
  4796. }
  4797. _SOKOL_PRIVATE int _sapp_android_input_cb(int fd, int events, void* data) {
  4798. if ((events & ALOOPER_EVENT_INPUT) == 0) {
  4799. SOKOL_LOG("_sapp_android_input_cb() encountered unsupported event");
  4800. return 1;
  4801. }
  4802. _sapp_android_state_t* state = &_sapp_android_state;;
  4803. SOKOL_ASSERT(state->current.input);
  4804. AInputEvent* event = NULL;
  4805. while (AInputQueue_getEvent(state->current.input, &event) >= 0) {
  4806. if (AInputQueue_preDispatchEvent(state->current.input, event) != 0) {
  4807. continue;
  4808. }
  4809. int32_t handled = 0;
  4810. if (_sapp_android_touch_event(event) || _sapp_android_key_event(event)) {
  4811. handled = 1;
  4812. }
  4813. AInputQueue_finishEvent(state->current.input, event, handled);
  4814. }
  4815. return 1;
  4816. }
  4817. _SOKOL_PRIVATE int _sapp_android_main_cb(int fd, int events, void* data) {
  4818. if ((events & ALOOPER_EVENT_INPUT) == 0) {
  4819. SOKOL_LOG("_sapp_android_main_cb() encountered unsupported event");
  4820. return 1;
  4821. }
  4822. _sapp_android_state_t* state = &_sapp_android_state;
  4823. _sapp_android_msg_t msg;
  4824. if (read(fd, &msg, sizeof(msg)) != sizeof(msg)) {
  4825. SOKOL_LOG("Could not write to read_from_main_fd");
  4826. return 1;
  4827. }
  4828. pthread_mutex_lock(&state->pt.mutex);
  4829. switch (msg) {
  4830. case _SOKOL_ANDROID_MSG_CREATE:
  4831. {
  4832. SOKOL_LOG("MSG_CREATE");
  4833. SOKOL_ASSERT(!_sapp.valid);
  4834. bool result = _sapp_android_init_egl();
  4835. SOKOL_ASSERT(result);
  4836. _sapp.valid = true;
  4837. state->has_created = true;
  4838. }
  4839. break;
  4840. case _SOKOL_ANDROID_MSG_RESUME:
  4841. SOKOL_LOG("MSG_RESUME");
  4842. state->has_resumed = true;
  4843. _sapp_android_app_event(SAPP_EVENTTYPE_RESUMED);
  4844. break;
  4845. case _SOKOL_ANDROID_MSG_PAUSE:
  4846. SOKOL_LOG("MSG_PAUSE");
  4847. state->has_resumed = false;
  4848. _sapp_android_app_event(SAPP_EVENTTYPE_SUSPENDED);
  4849. break;
  4850. case _SOKOL_ANDROID_MSG_FOCUS:
  4851. SOKOL_LOG("MSG_FOCUS");
  4852. state->has_focus = true;
  4853. break;
  4854. case _SOKOL_ANDROID_MSG_NO_FOCUS:
  4855. SOKOL_LOG("MSG_NO_FOCUS");
  4856. state->has_focus = false;
  4857. break;
  4858. case _SOKOL_ANDROID_MSG_SET_NATIVE_WINDOW:
  4859. SOKOL_LOG("MSG_SET_NATIVE_WINDOW");
  4860. if (state->current.window != state->pending.window) {
  4861. if (state->current.window != NULL) {
  4862. _sapp_android_cleanup_egl_surface();
  4863. }
  4864. if (state->pending.window != NULL) {
  4865. SOKOL_LOG("Creating egl surface ...");
  4866. if (_sapp_android_init_egl_surface(state->pending.window)) {
  4867. SOKOL_LOG("... ok!");
  4868. _sapp_android_update_dimensions(state->pending.window, true);
  4869. } else {
  4870. SOKOL_LOG("... failed!");
  4871. _sapp_android_shutdown();
  4872. }
  4873. }
  4874. }
  4875. state->current.window = state->pending.window;
  4876. break;
  4877. case _SOKOL_ANDROID_MSG_SET_INPUT_QUEUE:
  4878. SOKOL_LOG("MSG_SET_INPUT_QUEUE");
  4879. if (state->current.input != state->pending.input) {
  4880. if (state->current.input != NULL) {
  4881. AInputQueue_detachLooper(state->current.input);
  4882. }
  4883. if (state->pending.input != NULL) {
  4884. AInputQueue_attachLooper(
  4885. state->pending.input,
  4886. state->looper,
  4887. ALOOPER_POLL_CALLBACK,
  4888. _sapp_android_input_cb,
  4889. NULL); /* data */
  4890. }
  4891. }
  4892. state->current.input = state->pending.input;
  4893. break;
  4894. case _SOKOL_ANDROID_MSG_DESTROY:
  4895. SOKOL_LOG("MSG_DESTROY");
  4896. _sapp_android_cleanup();
  4897. _sapp.valid = false;
  4898. state->is_thread_stopping = true;
  4899. break;
  4900. default:
  4901. SOKOL_LOG("Unknown msg type received");
  4902. break;
  4903. }
  4904. pthread_cond_broadcast(&state->pt.cond); /* signal "received" */
  4905. pthread_mutex_unlock(&state->pt.mutex);
  4906. return 1;
  4907. }
  4908. _SOKOL_PRIVATE bool _sapp_android_should_update(void) {
  4909. bool is_in_front = _sapp_android_state.has_resumed && _sapp_android_state.has_focus;
  4910. bool has_surface = _sapp_android_state.surface != EGL_NO_SURFACE;
  4911. return is_in_front && has_surface;
  4912. }
  4913. _SOKOL_PRIVATE void _sapp_android_show_keyboard(bool shown) {
  4914. SOKOL_ASSERT(_sapp.valid);
  4915. /* This seems to be broken in the NDK, but there is (a very cumbersome) workaround... */
  4916. if (shown) {
  4917. SOKOL_LOG("Showing keyboard");
  4918. ANativeActivity_showSoftInput(_sapp_android_state.activity, ANATIVEACTIVITY_SHOW_SOFT_INPUT_FORCED);
  4919. } else {
  4920. SOKOL_LOG("Hiding keyboard");
  4921. ANativeActivity_hideSoftInput(_sapp_android_state.activity, ANATIVEACTIVITY_HIDE_SOFT_INPUT_NOT_ALWAYS);
  4922. }
  4923. }
  4924. _SOKOL_PRIVATE void* _sapp_android_loop(void* obj) {
  4925. SOKOL_LOG("Loop thread started");
  4926. _sapp_android_state_t* state = (_sapp_android_state_t*)obj;
  4927. state->looper = ALooper_prepare(0 /* or ALOOPER_PREPARE_ALLOW_NON_CALLBACKS*/);
  4928. ALooper_addFd(state->looper,
  4929. state->pt.read_from_main_fd,
  4930. ALOOPER_POLL_CALLBACK,
  4931. ALOOPER_EVENT_INPUT,
  4932. _sapp_android_main_cb,
  4933. NULL); /* data */
  4934. /* signal start to main thread */
  4935. pthread_mutex_lock(&state->pt.mutex);
  4936. state->is_thread_started = true;
  4937. pthread_cond_broadcast(&state->pt.cond);
  4938. pthread_mutex_unlock(&state->pt.mutex);
  4939. /* main loop */
  4940. while (!state->is_thread_stopping) {
  4941. /* sokol frame */
  4942. if (_sapp_android_should_update()) {
  4943. _sapp_android_frame();
  4944. }
  4945. /* process all events (or stop early if app is requested to quit) */
  4946. bool process_events = true;
  4947. while (process_events && !state->is_thread_stopping) {
  4948. bool block_until_event = !state->is_thread_stopping && !_sapp_android_should_update();
  4949. process_events = ALooper_pollOnce(block_until_event ? -1 : 0, NULL, NULL, NULL) == ALOOPER_POLL_CALLBACK;
  4950. }
  4951. }
  4952. /* cleanup thread */
  4953. if (state->current.input != NULL) {
  4954. AInputQueue_detachLooper(state->current.input);
  4955. }
  4956. /* the following causes heap corruption on exit, why??
  4957. ALooper_removeFd(state->looper, state->pt.read_from_main_fd);
  4958. ALooper_release(state->looper);*/
  4959. /* signal "destroyed" */
  4960. pthread_mutex_lock(&state->pt.mutex);
  4961. state->is_thread_stopped = true;
  4962. pthread_cond_broadcast(&state->pt.cond);
  4963. pthread_mutex_unlock(&state->pt.mutex);
  4964. SOKOL_LOG("Loop thread done");
  4965. return NULL;
  4966. }
  4967. /* android main/ui thread */
  4968. _SOKOL_PRIVATE void _sapp_android_msg(_sapp_android_state_t* state, _sapp_android_msg_t msg) {
  4969. if (write(state->pt.write_from_main_fd, &msg, sizeof(msg)) != sizeof(msg)) {
  4970. SOKOL_LOG("Could not write to write_from_main_fd");
  4971. }
  4972. }
  4973. _SOKOL_PRIVATE void _sapp_android_on_start(ANativeActivity* activity) {
  4974. SOKOL_LOG("NativeActivity onStart()");
  4975. }
  4976. _SOKOL_PRIVATE void _sapp_android_on_resume(ANativeActivity* activity) {
  4977. SOKOL_LOG("NativeActivity onResume()");
  4978. _sapp_android_msg(&_sapp_android_state, _SOKOL_ANDROID_MSG_RESUME);
  4979. }
  4980. _SOKOL_PRIVATE void* _sapp_android_on_save_instance_state(ANativeActivity* activity, size_t* out_size) {
  4981. SOKOL_LOG("NativeActivity onSaveInstanceState()");
  4982. *out_size = 0;
  4983. return NULL;
  4984. }
  4985. _SOKOL_PRIVATE void _sapp_android_on_window_focus_changed(ANativeActivity* activity, int has_focus) {
  4986. SOKOL_LOG("NativeActivity onWindowFocusChanged()");
  4987. if (has_focus) {
  4988. _sapp_android_msg(&_sapp_android_state, _SOKOL_ANDROID_MSG_FOCUS);
  4989. } else {
  4990. _sapp_android_msg(&_sapp_android_state, _SOKOL_ANDROID_MSG_NO_FOCUS);
  4991. }
  4992. }
  4993. _SOKOL_PRIVATE void _sapp_android_on_pause(ANativeActivity* activity) {
  4994. SOKOL_LOG("NativeActivity onPause()");
  4995. _sapp_android_msg(&_sapp_android_state, _SOKOL_ANDROID_MSG_PAUSE);
  4996. }
  4997. _SOKOL_PRIVATE void _sapp_android_on_stop(ANativeActivity* activity) {
  4998. SOKOL_LOG("NativeActivity onStop()");
  4999. }
  5000. _SOKOL_PRIVATE void _sapp_android_msg_set_native_window(_sapp_android_state_t* state, ANativeWindow* window) {
  5001. pthread_mutex_lock(&state->pt.mutex);
  5002. state->pending.window = window;
  5003. _sapp_android_msg(state, _SOKOL_ANDROID_MSG_SET_NATIVE_WINDOW);
  5004. while (state->current.window != window) {
  5005. pthread_cond_wait(&state->pt.cond, &state->pt.mutex);
  5006. }
  5007. pthread_mutex_unlock(&state->pt.mutex);
  5008. }
  5009. _SOKOL_PRIVATE void _sapp_android_on_native_window_created(ANativeActivity* activity, ANativeWindow* window) {
  5010. SOKOL_LOG("NativeActivity onNativeWindowCreated()");
  5011. _sapp_android_msg_set_native_window(&_sapp_android_state, window);
  5012. }
  5013. _SOKOL_PRIVATE void _sapp_android_on_native_window_destroyed(ANativeActivity* activity, ANativeWindow* window) {
  5014. SOKOL_LOG("NativeActivity onNativeWindowDestroyed()");
  5015. _sapp_android_msg_set_native_window(&_sapp_android_state, NULL);
  5016. }
  5017. _SOKOL_PRIVATE void _sapp_android_msg_set_input_queue(_sapp_android_state_t* state, AInputQueue* input) {
  5018. pthread_mutex_lock(&state->pt.mutex);
  5019. state->pending.input = input;
  5020. _sapp_android_msg(state, _SOKOL_ANDROID_MSG_SET_INPUT_QUEUE);
  5021. while (state->current.input != input) {
  5022. pthread_cond_wait(&state->pt.cond, &state->pt.mutex);
  5023. }
  5024. pthread_mutex_unlock(&state->pt.mutex);
  5025. }
  5026. _SOKOL_PRIVATE void _sapp_android_on_input_queue_created(ANativeActivity* activity, AInputQueue* queue) {
  5027. SOKOL_LOG("NativeActivity onInputQueueCreated()");
  5028. _sapp_android_msg_set_input_queue(&_sapp_android_state, queue);
  5029. }
  5030. _SOKOL_PRIVATE void _sapp_android_on_input_queue_destroyed(ANativeActivity* activity, AInputQueue* queue) {
  5031. SOKOL_LOG("NativeActivity onInputQueueDestroyed()");
  5032. _sapp_android_msg_set_input_queue(&_sapp_android_state, NULL);
  5033. }
  5034. _SOKOL_PRIVATE void _sapp_android_on_config_changed(ANativeActivity* activity) {
  5035. SOKOL_LOG("NativeActivity onConfigurationChanged()");
  5036. /* see android:configChanges in manifest */
  5037. }
  5038. _SOKOL_PRIVATE void _sapp_android_on_low_memory(ANativeActivity* activity) {
  5039. SOKOL_LOG("NativeActivity onLowMemory()");
  5040. }
  5041. _SOKOL_PRIVATE void _sapp_android_on_destroy(ANativeActivity* activity) {
  5042. /*
  5043. * For some reason even an empty app using nativeactivity.h will crash (WIN DEATH)
  5044. * on my device (Moto X 2nd gen) when the app is removed from the task view
  5045. * (TaskStackView: onTaskViewDismissed).
  5046. *
  5047. * However, if ANativeActivity_finish() is explicitly called from for example
  5048. * _sapp_android_on_stop(), the crash disappears. Is this a bug in NativeActivity?
  5049. */
  5050. SOKOL_LOG("NativeActivity onDestroy()");
  5051. _sapp_android_state_t* state = &_sapp_android_state;
  5052. /* send destroy msg */
  5053. pthread_mutex_lock(&state->pt.mutex);
  5054. _sapp_android_msg(state, _SOKOL_ANDROID_MSG_DESTROY);
  5055. while (!_sapp_android_state.is_thread_stopped) {
  5056. pthread_cond_wait(&state->pt.cond, &state->pt.mutex);
  5057. }
  5058. pthread_mutex_unlock(&state->pt.mutex);
  5059. /* clean up main thread */
  5060. pthread_cond_destroy(&state->pt.cond);
  5061. pthread_mutex_destroy(&state->pt.mutex);
  5062. close(state->pt.read_from_main_fd);
  5063. close(state->pt.write_from_main_fd);
  5064. SOKOL_LOG("NativeActivity done");
  5065. /* this is a bit naughty, but causes a clean restart of the app (static globals are reset) */
  5066. exit(0);
  5067. }
  5068. JNIEXPORT
  5069. void ANativeActivity_onCreate(ANativeActivity* activity, void* saved_state, size_t saved_state_size) {
  5070. SOKOL_LOG("NativeActivity onCreate()");
  5071. sapp_desc desc = sokol_main(0, NULL);
  5072. _sapp_init_state(&desc);
  5073. /* start loop thread */
  5074. _sapp_android_state = (_sapp_android_state_t){0};
  5075. _sapp_android_state_t* state = &_sapp_android_state;
  5076. state->activity = activity;
  5077. int pipe_fd[2];
  5078. if (pipe(pipe_fd) != 0) {
  5079. SOKOL_LOG("Could not create thread pipe");
  5080. return;
  5081. }
  5082. state->pt.read_from_main_fd = pipe_fd[0];
  5083. state->pt.write_from_main_fd = pipe_fd[1];
  5084. pthread_mutex_init(&state->pt.mutex, NULL);
  5085. pthread_cond_init(&state->pt.cond, NULL);
  5086. pthread_attr_t attr;
  5087. pthread_attr_init(&attr);
  5088. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
  5089. pthread_create(&state->pt.thread, &attr, _sapp_android_loop, state);
  5090. pthread_attr_destroy(&attr);
  5091. /* wait until main loop has started */
  5092. pthread_mutex_lock(&state->pt.mutex);
  5093. while (!state->is_thread_started) {
  5094. pthread_cond_wait(&state->pt.cond, &state->pt.mutex);
  5095. }
  5096. pthread_mutex_unlock(&state->pt.mutex);
  5097. /* send create msg */
  5098. pthread_mutex_lock(&state->pt.mutex);
  5099. _sapp_android_msg(state, _SOKOL_ANDROID_MSG_CREATE);
  5100. while (!state->has_created) {
  5101. pthread_cond_wait(&state->pt.cond, &state->pt.mutex);
  5102. }
  5103. pthread_mutex_unlock(&state->pt.mutex);
  5104. /* register for callbacks */
  5105. activity->instance = state;
  5106. activity->callbacks->onStart = _sapp_android_on_start;
  5107. activity->callbacks->onResume = _sapp_android_on_resume;
  5108. activity->callbacks->onSaveInstanceState = _sapp_android_on_save_instance_state;
  5109. activity->callbacks->onWindowFocusChanged = _sapp_android_on_window_focus_changed;
  5110. activity->callbacks->onPause = _sapp_android_on_pause;
  5111. activity->callbacks->onStop = _sapp_android_on_stop;
  5112. activity->callbacks->onDestroy = _sapp_android_on_destroy;
  5113. activity->callbacks->onNativeWindowCreated = _sapp_android_on_native_window_created;
  5114. /* activity->callbacks->onNativeWindowResized = _sapp_android_on_native_window_resized; */
  5115. /* activity->callbacks->onNativeWindowRedrawNeeded = _sapp_android_on_native_window_redraw_needed; */
  5116. activity->callbacks->onNativeWindowDestroyed = _sapp_android_on_native_window_destroyed;
  5117. activity->callbacks->onInputQueueCreated = _sapp_android_on_input_queue_created;
  5118. activity->callbacks->onInputQueueDestroyed = _sapp_android_on_input_queue_destroyed;
  5119. /* activity->callbacks->onContentRectChanged = _sapp_android_on_content_rect_changed; */
  5120. activity->callbacks->onConfigurationChanged = _sapp_android_on_config_changed;
  5121. activity->callbacks->onLowMemory = _sapp_android_on_low_memory;
  5122. SOKOL_LOG("NativeActivity successfully created");
  5123. /* NOT A BUG: do NOT call sapp_discard_state() */
  5124. }
  5125. #endif /* Android */
  5126. /*== LINUX ==================================================================*/
  5127. #if (defined(__linux__) || defined(__unix__)) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__)
  5128. #define GL_GLEXT_PROTOTYPES
  5129. #include <X11/X.h>
  5130. #include <X11/Xlib.h>
  5131. #include <X11/XKBlib.h>
  5132. #include <X11/Xresource.h>
  5133. #include <X11/extensions/Xrandr.h>
  5134. #include <X11/Xmd.h> /* CARD32 */
  5135. #include <GL/gl.h>
  5136. #include <dlfcn.h> /* dlopen, dlsym, dlclose */
  5137. #include <limits.h> /* LONG_MAX */
  5138. #define GLX_VENDOR 1
  5139. #define GLX_RGBA_BIT 0x00000001
  5140. #define GLX_WINDOW_BIT 0x00000001
  5141. #define GLX_DRAWABLE_TYPE 0x8010
  5142. #define GLX_RENDER_TYPE 0x8011
  5143. #define GLX_RGBA_TYPE 0x8014
  5144. #define GLX_DOUBLEBUFFER 5
  5145. #define GLX_STEREO 6
  5146. #define GLX_AUX_BUFFERS 7
  5147. #define GLX_RED_SIZE 8
  5148. #define GLX_GREEN_SIZE 9
  5149. #define GLX_BLUE_SIZE 10
  5150. #define GLX_ALPHA_SIZE 11
  5151. #define GLX_DEPTH_SIZE 12
  5152. #define GLX_STENCIL_SIZE 13
  5153. #define GLX_ACCUM_RED_SIZE 14
  5154. #define GLX_ACCUM_GREEN_SIZE 15
  5155. #define GLX_ACCUM_BLUE_SIZE 16
  5156. #define GLX_ACCUM_ALPHA_SIZE 17
  5157. #define GLX_SAMPLES 0x186a1
  5158. #define GLX_VISUAL_ID 0x800b
  5159. #define GLX_FRAMEBUFFER_SRGB_CAPABLE_ARB 0x20b2
  5160. #define GLX_CONTEXT_DEBUG_BIT_ARB 0x00000001
  5161. #define GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB 0x00000002
  5162. #define GLX_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
  5163. #define GLX_CONTEXT_PROFILE_MASK_ARB 0x9126
  5164. #define GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
  5165. #define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091
  5166. #define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092
  5167. #define GLX_CONTEXT_FLAGS_ARB 0x2094
  5168. #define GLX_CONTEXT_ROBUST_ACCESS_BIT_ARB 0x00000004
  5169. #define GLX_LOSE_CONTEXT_ON_RESET_ARB 0x8252
  5170. #define GLX_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB 0x8256
  5171. #define GLX_NO_RESET_NOTIFICATION_ARB 0x8261
  5172. #define GLX_CONTEXT_RELEASE_BEHAVIOR_ARB 0x2097
  5173. #define GLX_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB 0
  5174. #define GLX_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB 0x2098
  5175. typedef XID GLXWindow;
  5176. typedef XID GLXDrawable;
  5177. typedef struct __GLXFBConfig* GLXFBConfig;
  5178. typedef struct __GLXcontext* GLXContext;
  5179. typedef void (*__GLXextproc)(void);
  5180. typedef int (*PFNGLXGETFBCONFIGATTRIBPROC)(Display*,GLXFBConfig,int,int*);
  5181. typedef const char* (*PFNGLXGETCLIENTSTRINGPROC)(Display*,int);
  5182. typedef Bool (*PFNGLXQUERYEXTENSIONPROC)(Display*,int*,int*);
  5183. typedef Bool (*PFNGLXQUERYVERSIONPROC)(Display*,int*,int*);
  5184. typedef void (*PFNGLXDESTROYCONTEXTPROC)(Display*,GLXContext);
  5185. typedef Bool (*PFNGLXMAKECURRENTPROC)(Display*,GLXDrawable,GLXContext);
  5186. typedef void (*PFNGLXSWAPBUFFERSPROC)(Display*,GLXDrawable);
  5187. typedef const char* (*PFNGLXQUERYEXTENSIONSSTRINGPROC)(Display*,int);
  5188. typedef GLXFBConfig* (*PFNGLXGETFBCONFIGSPROC)(Display*,int,int*);
  5189. typedef GLXContext (*PFNGLXCREATENEWCONTEXTPROC)(Display*,GLXFBConfig,int,GLXContext,Bool);
  5190. typedef __GLXextproc (* PFNGLXGETPROCADDRESSPROC)(const GLubyte *procName);
  5191. typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int);
  5192. typedef XVisualInfo* (*PFNGLXGETVISUALFROMFBCONFIGPROC)(Display*,GLXFBConfig);
  5193. typedef GLXWindow (*PFNGLXCREATEWINDOWPROC)(Display*,GLXFBConfig,Window,const int*);
  5194. typedef void (*PFNGLXDESTROYWINDOWPROC)(Display*,GLXWindow);
  5195. typedef int (*PFNGLXSWAPINTERVALMESAPROC)(int);
  5196. typedef GLXContext (*PFNGLXCREATECONTEXTATTRIBSARBPROC)(Display*,GLXFBConfig,GLXContext,Bool,const int*);
  5197. static Display* _sapp_x11_display;
  5198. static int _sapp_x11_screen;
  5199. static Window _sapp_x11_root;
  5200. static Colormap _sapp_x11_colormap;
  5201. static Window _sapp_x11_window;
  5202. static float _sapp_x11_dpi;
  5203. static int _sapp_x11_window_state;
  5204. static unsigned char _sapp_x11_error_code;
  5205. static void* _sapp_glx_libgl;
  5206. static int _sapp_glx_major;
  5207. static int _sapp_glx_minor;
  5208. static int _sapp_glx_eventbase;
  5209. static int _sapp_glx_errorbase;
  5210. static GLXContext _sapp_glx_ctx;
  5211. static GLXWindow _sapp_glx_window;
  5212. static Atom _sapp_x11_UTF8_STRING;
  5213. static Atom _sapp_x11_WM_PROTOCOLS;
  5214. static Atom _sapp_x11_WM_DELETE_WINDOW;
  5215. static Atom _sapp_x11_WM_STATE;
  5216. static Atom _sapp_x11_NET_WM_NAME;
  5217. static Atom _sapp_x11_NET_WM_ICON_NAME;
  5218. // GLX 1.3 functions
  5219. static PFNGLXGETFBCONFIGSPROC _sapp_glx_GetFBConfigs;
  5220. static PFNGLXGETFBCONFIGATTRIBPROC _sapp_glx_GetFBConfigAttrib;
  5221. static PFNGLXGETCLIENTSTRINGPROC _sapp_glx_GetClientString;
  5222. static PFNGLXQUERYEXTENSIONPROC _sapp_glx_QueryExtension;
  5223. static PFNGLXQUERYVERSIONPROC _sapp_glx_QueryVersion;
  5224. static PFNGLXDESTROYCONTEXTPROC _sapp_glx_DestroyContext;
  5225. static PFNGLXMAKECURRENTPROC _sapp_glx_MakeCurrent;
  5226. static PFNGLXSWAPBUFFERSPROC _sapp_glx_SwapBuffers;
  5227. static PFNGLXQUERYEXTENSIONSSTRINGPROC _sapp_glx_QueryExtensionsString;
  5228. static PFNGLXCREATENEWCONTEXTPROC _sapp_glx_CreateNewContext;
  5229. static PFNGLXGETVISUALFROMFBCONFIGPROC _sapp_glx_GetVisualFromFBConfig;
  5230. static PFNGLXCREATEWINDOWPROC _sapp_glx_CreateWindow;
  5231. static PFNGLXDESTROYWINDOWPROC _sapp_glx_DestroyWindow;
  5232. // GLX 1.4 and extension functions
  5233. static PFNGLXGETPROCADDRESSPROC _sapp_glx_GetProcAddress;
  5234. static PFNGLXGETPROCADDRESSPROC _sapp_glx_GetProcAddressARB;
  5235. static PFNGLXSWAPINTERVALEXTPROC _sapp_glx_SwapIntervalEXT;
  5236. static PFNGLXSWAPINTERVALMESAPROC _sapp_glx_SwapIntervalMESA;
  5237. static PFNGLXCREATECONTEXTATTRIBSARBPROC _sapp_glx_CreateContextAttribsARB;
  5238. static bool _sapp_glx_EXT_swap_control;
  5239. static bool _sapp_glx_MESA_swap_control;
  5240. static bool _sapp_glx_ARB_multisample;
  5241. static bool _sapp_glx_ARB_framebuffer_sRGB;
  5242. static bool _sapp_glx_EXT_framebuffer_sRGB;
  5243. static bool _sapp_glx_ARB_create_context;
  5244. static bool _sapp_glx_ARB_create_context_profile;
  5245. /* see GLFW's xkb_unicode.c */
  5246. static const struct _sapp_x11_codepair {
  5247. uint16_t keysym;
  5248. uint16_t ucs;
  5249. } _sapp_x11_keysymtab[] = {
  5250. { 0x01a1, 0x0104 },
  5251. { 0x01a2, 0x02d8 },
  5252. { 0x01a3, 0x0141 },
  5253. { 0x01a5, 0x013d },
  5254. { 0x01a6, 0x015a },
  5255. { 0x01a9, 0x0160 },
  5256. { 0x01aa, 0x015e },
  5257. { 0x01ab, 0x0164 },
  5258. { 0x01ac, 0x0179 },
  5259. { 0x01ae, 0x017d },
  5260. { 0x01af, 0x017b },
  5261. { 0x01b1, 0x0105 },
  5262. { 0x01b2, 0x02db },
  5263. { 0x01b3, 0x0142 },
  5264. { 0x01b5, 0x013e },
  5265. { 0x01b6, 0x015b },
  5266. { 0x01b7, 0x02c7 },
  5267. { 0x01b9, 0x0161 },
  5268. { 0x01ba, 0x015f },
  5269. { 0x01bb, 0x0165 },
  5270. { 0x01bc, 0x017a },
  5271. { 0x01bd, 0x02dd },
  5272. { 0x01be, 0x017e },
  5273. { 0x01bf, 0x017c },
  5274. { 0x01c0, 0x0154 },
  5275. { 0x01c3, 0x0102 },
  5276. { 0x01c5, 0x0139 },
  5277. { 0x01c6, 0x0106 },
  5278. { 0x01c8, 0x010c },
  5279. { 0x01ca, 0x0118 },
  5280. { 0x01cc, 0x011a },
  5281. { 0x01cf, 0x010e },
  5282. { 0x01d0, 0x0110 },
  5283. { 0x01d1, 0x0143 },
  5284. { 0x01d2, 0x0147 },
  5285. { 0x01d5, 0x0150 },
  5286. { 0x01d8, 0x0158 },
  5287. { 0x01d9, 0x016e },
  5288. { 0x01db, 0x0170 },
  5289. { 0x01de, 0x0162 },
  5290. { 0x01e0, 0x0155 },
  5291. { 0x01e3, 0x0103 },
  5292. { 0x01e5, 0x013a },
  5293. { 0x01e6, 0x0107 },
  5294. { 0x01e8, 0x010d },
  5295. { 0x01ea, 0x0119 },
  5296. { 0x01ec, 0x011b },
  5297. { 0x01ef, 0x010f },
  5298. { 0x01f0, 0x0111 },
  5299. { 0x01f1, 0x0144 },
  5300. { 0x01f2, 0x0148 },
  5301. { 0x01f5, 0x0151 },
  5302. { 0x01f8, 0x0159 },
  5303. { 0x01f9, 0x016f },
  5304. { 0x01fb, 0x0171 },
  5305. { 0x01fe, 0x0163 },
  5306. { 0x01ff, 0x02d9 },
  5307. { 0x02a1, 0x0126 },
  5308. { 0x02a6, 0x0124 },
  5309. { 0x02a9, 0x0130 },
  5310. { 0x02ab, 0x011e },
  5311. { 0x02ac, 0x0134 },
  5312. { 0x02b1, 0x0127 },
  5313. { 0x02b6, 0x0125 },
  5314. { 0x02b9, 0x0131 },
  5315. { 0x02bb, 0x011f },
  5316. { 0x02bc, 0x0135 },
  5317. { 0x02c5, 0x010a },
  5318. { 0x02c6, 0x0108 },
  5319. { 0x02d5, 0x0120 },
  5320. { 0x02d8, 0x011c },
  5321. { 0x02dd, 0x016c },
  5322. { 0x02de, 0x015c },
  5323. { 0x02e5, 0x010b },
  5324. { 0x02e6, 0x0109 },
  5325. { 0x02f5, 0x0121 },
  5326. { 0x02f8, 0x011d },
  5327. { 0x02fd, 0x016d },
  5328. { 0x02fe, 0x015d },
  5329. { 0x03a2, 0x0138 },
  5330. { 0x03a3, 0x0156 },
  5331. { 0x03a5, 0x0128 },
  5332. { 0x03a6, 0x013b },
  5333. { 0x03aa, 0x0112 },
  5334. { 0x03ab, 0x0122 },
  5335. { 0x03ac, 0x0166 },
  5336. { 0x03b3, 0x0157 },
  5337. { 0x03b5, 0x0129 },
  5338. { 0x03b6, 0x013c },
  5339. { 0x03ba, 0x0113 },
  5340. { 0x03bb, 0x0123 },
  5341. { 0x03bc, 0x0167 },
  5342. { 0x03bd, 0x014a },
  5343. { 0x03bf, 0x014b },
  5344. { 0x03c0, 0x0100 },
  5345. { 0x03c7, 0x012e },
  5346. { 0x03cc, 0x0116 },
  5347. { 0x03cf, 0x012a },
  5348. { 0x03d1, 0x0145 },
  5349. { 0x03d2, 0x014c },
  5350. { 0x03d3, 0x0136 },
  5351. { 0x03d9, 0x0172 },
  5352. { 0x03dd, 0x0168 },
  5353. { 0x03de, 0x016a },
  5354. { 0x03e0, 0x0101 },
  5355. { 0x03e7, 0x012f },
  5356. { 0x03ec, 0x0117 },
  5357. { 0x03ef, 0x012b },
  5358. { 0x03f1, 0x0146 },
  5359. { 0x03f2, 0x014d },
  5360. { 0x03f3, 0x0137 },
  5361. { 0x03f9, 0x0173 },
  5362. { 0x03fd, 0x0169 },
  5363. { 0x03fe, 0x016b },
  5364. { 0x047e, 0x203e },
  5365. { 0x04a1, 0x3002 },
  5366. { 0x04a2, 0x300c },
  5367. { 0x04a3, 0x300d },
  5368. { 0x04a4, 0x3001 },
  5369. { 0x04a5, 0x30fb },
  5370. { 0x04a6, 0x30f2 },
  5371. { 0x04a7, 0x30a1 },
  5372. { 0x04a8, 0x30a3 },
  5373. { 0x04a9, 0x30a5 },
  5374. { 0x04aa, 0x30a7 },
  5375. { 0x04ab, 0x30a9 },
  5376. { 0x04ac, 0x30e3 },
  5377. { 0x04ad, 0x30e5 },
  5378. { 0x04ae, 0x30e7 },
  5379. { 0x04af, 0x30c3 },
  5380. { 0x04b0, 0x30fc },
  5381. { 0x04b1, 0x30a2 },
  5382. { 0x04b2, 0x30a4 },
  5383. { 0x04b3, 0x30a6 },
  5384. { 0x04b4, 0x30a8 },
  5385. { 0x04b5, 0x30aa },
  5386. { 0x04b6, 0x30ab },
  5387. { 0x04b7, 0x30ad },
  5388. { 0x04b8, 0x30af },
  5389. { 0x04b9, 0x30b1 },
  5390. { 0x04ba, 0x30b3 },
  5391. { 0x04bb, 0x30b5 },
  5392. { 0x04bc, 0x30b7 },
  5393. { 0x04bd, 0x30b9 },
  5394. { 0x04be, 0x30bb },
  5395. { 0x04bf, 0x30bd },
  5396. { 0x04c0, 0x30bf },
  5397. { 0x04c1, 0x30c1 },
  5398. { 0x04c2, 0x30c4 },
  5399. { 0x04c3, 0x30c6 },
  5400. { 0x04c4, 0x30c8 },
  5401. { 0x04c5, 0x30ca },
  5402. { 0x04c6, 0x30cb },
  5403. { 0x04c7, 0x30cc },
  5404. { 0x04c8, 0x30cd },
  5405. { 0x04c9, 0x30ce },
  5406. { 0x04ca, 0x30cf },
  5407. { 0x04cb, 0x30d2 },
  5408. { 0x04cc, 0x30d5 },
  5409. { 0x04cd, 0x30d8 },
  5410. { 0x04ce, 0x30db },
  5411. { 0x04cf, 0x30de },
  5412. { 0x04d0, 0x30df },
  5413. { 0x04d1, 0x30e0 },
  5414. { 0x04d2, 0x30e1 },
  5415. { 0x04d3, 0x30e2 },
  5416. { 0x04d4, 0x30e4 },
  5417. { 0x04d5, 0x30e6 },
  5418. { 0x04d6, 0x30e8 },
  5419. { 0x04d7, 0x30e9 },
  5420. { 0x04d8, 0x30ea },
  5421. { 0x04d9, 0x30eb },
  5422. { 0x04da, 0x30ec },
  5423. { 0x04db, 0x30ed },
  5424. { 0x04dc, 0x30ef },
  5425. { 0x04dd, 0x30f3 },
  5426. { 0x04de, 0x309b },
  5427. { 0x04df, 0x309c },
  5428. { 0x05ac, 0x060c },
  5429. { 0x05bb, 0x061b },
  5430. { 0x05bf, 0x061f },
  5431. { 0x05c1, 0x0621 },
  5432. { 0x05c2, 0x0622 },
  5433. { 0x05c3, 0x0623 },
  5434. { 0x05c4, 0x0624 },
  5435. { 0x05c5, 0x0625 },
  5436. { 0x05c6, 0x0626 },
  5437. { 0x05c7, 0x0627 },
  5438. { 0x05c8, 0x0628 },
  5439. { 0x05c9, 0x0629 },
  5440. { 0x05ca, 0x062a },
  5441. { 0x05cb, 0x062b },
  5442. { 0x05cc, 0x062c },
  5443. { 0x05cd, 0x062d },
  5444. { 0x05ce, 0x062e },
  5445. { 0x05cf, 0x062f },
  5446. { 0x05d0, 0x0630 },
  5447. { 0x05d1, 0x0631 },
  5448. { 0x05d2, 0x0632 },
  5449. { 0x05d3, 0x0633 },
  5450. { 0x05d4, 0x0634 },
  5451. { 0x05d5, 0x0635 },
  5452. { 0x05d6, 0x0636 },
  5453. { 0x05d7, 0x0637 },
  5454. { 0x05d8, 0x0638 },
  5455. { 0x05d9, 0x0639 },
  5456. { 0x05da, 0x063a },
  5457. { 0x05e0, 0x0640 },
  5458. { 0x05e1, 0x0641 },
  5459. { 0x05e2, 0x0642 },
  5460. { 0x05e3, 0x0643 },
  5461. { 0x05e4, 0x0644 },
  5462. { 0x05e5, 0x0645 },
  5463. { 0x05e6, 0x0646 },
  5464. { 0x05e7, 0x0647 },
  5465. { 0x05e8, 0x0648 },
  5466. { 0x05e9, 0x0649 },
  5467. { 0x05ea, 0x064a },
  5468. { 0x05eb, 0x064b },
  5469. { 0x05ec, 0x064c },
  5470. { 0x05ed, 0x064d },
  5471. { 0x05ee, 0x064e },
  5472. { 0x05ef, 0x064f },
  5473. { 0x05f0, 0x0650 },
  5474. { 0x05f1, 0x0651 },
  5475. { 0x05f2, 0x0652 },
  5476. { 0x06a1, 0x0452 },
  5477. { 0x06a2, 0x0453 },
  5478. { 0x06a3, 0x0451 },
  5479. { 0x06a4, 0x0454 },
  5480. { 0x06a5, 0x0455 },
  5481. { 0x06a6, 0x0456 },
  5482. { 0x06a7, 0x0457 },
  5483. { 0x06a8, 0x0458 },
  5484. { 0x06a9, 0x0459 },
  5485. { 0x06aa, 0x045a },
  5486. { 0x06ab, 0x045b },
  5487. { 0x06ac, 0x045c },
  5488. { 0x06ae, 0x045e },
  5489. { 0x06af, 0x045f },
  5490. { 0x06b0, 0x2116 },
  5491. { 0x06b1, 0x0402 },
  5492. { 0x06b2, 0x0403 },
  5493. { 0x06b3, 0x0401 },
  5494. { 0x06b4, 0x0404 },
  5495. { 0x06b5, 0x0405 },
  5496. { 0x06b6, 0x0406 },
  5497. { 0x06b7, 0x0407 },
  5498. { 0x06b8, 0x0408 },
  5499. { 0x06b9, 0x0409 },
  5500. { 0x06ba, 0x040a },
  5501. { 0x06bb, 0x040b },
  5502. { 0x06bc, 0x040c },
  5503. { 0x06be, 0x040e },
  5504. { 0x06bf, 0x040f },
  5505. { 0x06c0, 0x044e },
  5506. { 0x06c1, 0x0430 },
  5507. { 0x06c2, 0x0431 },
  5508. { 0x06c3, 0x0446 },
  5509. { 0x06c4, 0x0434 },
  5510. { 0x06c5, 0x0435 },
  5511. { 0x06c6, 0x0444 },
  5512. { 0x06c7, 0x0433 },
  5513. { 0x06c8, 0x0445 },
  5514. { 0x06c9, 0x0438 },
  5515. { 0x06ca, 0x0439 },
  5516. { 0x06cb, 0x043a },
  5517. { 0x06cc, 0x043b },
  5518. { 0x06cd, 0x043c },
  5519. { 0x06ce, 0x043d },
  5520. { 0x06cf, 0x043e },
  5521. { 0x06d0, 0x043f },
  5522. { 0x06d1, 0x044f },
  5523. { 0x06d2, 0x0440 },
  5524. { 0x06d3, 0x0441 },
  5525. { 0x06d4, 0x0442 },
  5526. { 0x06d5, 0x0443 },
  5527. { 0x06d6, 0x0436 },
  5528. { 0x06d7, 0x0432 },
  5529. { 0x06d8, 0x044c },
  5530. { 0x06d9, 0x044b },
  5531. { 0x06da, 0x0437 },
  5532. { 0x06db, 0x0448 },
  5533. { 0x06dc, 0x044d },
  5534. { 0x06dd, 0x0449 },
  5535. { 0x06de, 0x0447 },
  5536. { 0x06df, 0x044a },
  5537. { 0x06e0, 0x042e },
  5538. { 0x06e1, 0x0410 },
  5539. { 0x06e2, 0x0411 },
  5540. { 0x06e3, 0x0426 },
  5541. { 0x06e4, 0x0414 },
  5542. { 0x06e5, 0x0415 },
  5543. { 0x06e6, 0x0424 },
  5544. { 0x06e7, 0x0413 },
  5545. { 0x06e8, 0x0425 },
  5546. { 0x06e9, 0x0418 },
  5547. { 0x06ea, 0x0419 },
  5548. { 0x06eb, 0x041a },
  5549. { 0x06ec, 0x041b },
  5550. { 0x06ed, 0x041c },
  5551. { 0x06ee, 0x041d },
  5552. { 0x06ef, 0x041e },
  5553. { 0x06f0, 0x041f },
  5554. { 0x06f1, 0x042f },
  5555. { 0x06f2, 0x0420 },
  5556. { 0x06f3, 0x0421 },
  5557. { 0x06f4, 0x0422 },
  5558. { 0x06f5, 0x0423 },
  5559. { 0x06f6, 0x0416 },
  5560. { 0x06f7, 0x0412 },
  5561. { 0x06f8, 0x042c },
  5562. { 0x06f9, 0x042b },
  5563. { 0x06fa, 0x0417 },
  5564. { 0x06fb, 0x0428 },
  5565. { 0x06fc, 0x042d },
  5566. { 0x06fd, 0x0429 },
  5567. { 0x06fe, 0x0427 },
  5568. { 0x06ff, 0x042a },
  5569. { 0x07a1, 0x0386 },
  5570. { 0x07a2, 0x0388 },
  5571. { 0x07a3, 0x0389 },
  5572. { 0x07a4, 0x038a },
  5573. { 0x07a5, 0x03aa },
  5574. { 0x07a7, 0x038c },
  5575. { 0x07a8, 0x038e },
  5576. { 0x07a9, 0x03ab },
  5577. { 0x07ab, 0x038f },
  5578. { 0x07ae, 0x0385 },
  5579. { 0x07af, 0x2015 },
  5580. { 0x07b1, 0x03ac },
  5581. { 0x07b2, 0x03ad },
  5582. { 0x07b3, 0x03ae },
  5583. { 0x07b4, 0x03af },
  5584. { 0x07b5, 0x03ca },
  5585. { 0x07b6, 0x0390 },
  5586. { 0x07b7, 0x03cc },
  5587. { 0x07b8, 0x03cd },
  5588. { 0x07b9, 0x03cb },
  5589. { 0x07ba, 0x03b0 },
  5590. { 0x07bb, 0x03ce },
  5591. { 0x07c1, 0x0391 },
  5592. { 0x07c2, 0x0392 },
  5593. { 0x07c3, 0x0393 },
  5594. { 0x07c4, 0x0394 },
  5595. { 0x07c5, 0x0395 },
  5596. { 0x07c6, 0x0396 },
  5597. { 0x07c7, 0x0397 },
  5598. { 0x07c8, 0x0398 },
  5599. { 0x07c9, 0x0399 },
  5600. { 0x07ca, 0x039a },
  5601. { 0x07cb, 0x039b },
  5602. { 0x07cc, 0x039c },
  5603. { 0x07cd, 0x039d },
  5604. { 0x07ce, 0x039e },
  5605. { 0x07cf, 0x039f },
  5606. { 0x07d0, 0x03a0 },
  5607. { 0x07d1, 0x03a1 },
  5608. { 0x07d2, 0x03a3 },
  5609. { 0x07d4, 0x03a4 },
  5610. { 0x07d5, 0x03a5 },
  5611. { 0x07d6, 0x03a6 },
  5612. { 0x07d7, 0x03a7 },
  5613. { 0x07d8, 0x03a8 },
  5614. { 0x07d9, 0x03a9 },
  5615. { 0x07e1, 0x03b1 },
  5616. { 0x07e2, 0x03b2 },
  5617. { 0x07e3, 0x03b3 },
  5618. { 0x07e4, 0x03b4 },
  5619. { 0x07e5, 0x03b5 },
  5620. { 0x07e6, 0x03b6 },
  5621. { 0x07e7, 0x03b7 },
  5622. { 0x07e8, 0x03b8 },
  5623. { 0x07e9, 0x03b9 },
  5624. { 0x07ea, 0x03ba },
  5625. { 0x07eb, 0x03bb },
  5626. { 0x07ec, 0x03bc },
  5627. { 0x07ed, 0x03bd },
  5628. { 0x07ee, 0x03be },
  5629. { 0x07ef, 0x03bf },
  5630. { 0x07f0, 0x03c0 },
  5631. { 0x07f1, 0x03c1 },
  5632. { 0x07f2, 0x03c3 },
  5633. { 0x07f3, 0x03c2 },
  5634. { 0x07f4, 0x03c4 },
  5635. { 0x07f5, 0x03c5 },
  5636. { 0x07f6, 0x03c6 },
  5637. { 0x07f7, 0x03c7 },
  5638. { 0x07f8, 0x03c8 },
  5639. { 0x07f9, 0x03c9 },
  5640. { 0x08a1, 0x23b7 },
  5641. { 0x08a2, 0x250c },
  5642. { 0x08a3, 0x2500 },
  5643. { 0x08a4, 0x2320 },
  5644. { 0x08a5, 0x2321 },
  5645. { 0x08a6, 0x2502 },
  5646. { 0x08a7, 0x23a1 },
  5647. { 0x08a8, 0x23a3 },
  5648. { 0x08a9, 0x23a4 },
  5649. { 0x08aa, 0x23a6 },
  5650. { 0x08ab, 0x239b },
  5651. { 0x08ac, 0x239d },
  5652. { 0x08ad, 0x239e },
  5653. { 0x08ae, 0x23a0 },
  5654. { 0x08af, 0x23a8 },
  5655. { 0x08b0, 0x23ac },
  5656. { 0x08bc, 0x2264 },
  5657. { 0x08bd, 0x2260 },
  5658. { 0x08be, 0x2265 },
  5659. { 0x08bf, 0x222b },
  5660. { 0x08c0, 0x2234 },
  5661. { 0x08c1, 0x221d },
  5662. { 0x08c2, 0x221e },
  5663. { 0x08c5, 0x2207 },
  5664. { 0x08c8, 0x223c },
  5665. { 0x08c9, 0x2243 },
  5666. { 0x08cd, 0x21d4 },
  5667. { 0x08ce, 0x21d2 },
  5668. { 0x08cf, 0x2261 },
  5669. { 0x08d6, 0x221a },
  5670. { 0x08da, 0x2282 },
  5671. { 0x08db, 0x2283 },
  5672. { 0x08dc, 0x2229 },
  5673. { 0x08dd, 0x222a },
  5674. { 0x08de, 0x2227 },
  5675. { 0x08df, 0x2228 },
  5676. { 0x08ef, 0x2202 },
  5677. { 0x08f6, 0x0192 },
  5678. { 0x08fb, 0x2190 },
  5679. { 0x08fc, 0x2191 },
  5680. { 0x08fd, 0x2192 },
  5681. { 0x08fe, 0x2193 },
  5682. { 0x09e0, 0x25c6 },
  5683. { 0x09e1, 0x2592 },
  5684. { 0x09e2, 0x2409 },
  5685. { 0x09e3, 0x240c },
  5686. { 0x09e4, 0x240d },
  5687. { 0x09e5, 0x240a },
  5688. { 0x09e8, 0x2424 },
  5689. { 0x09e9, 0x240b },
  5690. { 0x09ea, 0x2518 },
  5691. { 0x09eb, 0x2510 },
  5692. { 0x09ec, 0x250c },
  5693. { 0x09ed, 0x2514 },
  5694. { 0x09ee, 0x253c },
  5695. { 0x09ef, 0x23ba },
  5696. { 0x09f0, 0x23bb },
  5697. { 0x09f1, 0x2500 },
  5698. { 0x09f2, 0x23bc },
  5699. { 0x09f3, 0x23bd },
  5700. { 0x09f4, 0x251c },
  5701. { 0x09f5, 0x2524 },
  5702. { 0x09f6, 0x2534 },
  5703. { 0x09f7, 0x252c },
  5704. { 0x09f8, 0x2502 },
  5705. { 0x0aa1, 0x2003 },
  5706. { 0x0aa2, 0x2002 },
  5707. { 0x0aa3, 0x2004 },
  5708. { 0x0aa4, 0x2005 },
  5709. { 0x0aa5, 0x2007 },
  5710. { 0x0aa6, 0x2008 },
  5711. { 0x0aa7, 0x2009 },
  5712. { 0x0aa8, 0x200a },
  5713. { 0x0aa9, 0x2014 },
  5714. { 0x0aaa, 0x2013 },
  5715. { 0x0aae, 0x2026 },
  5716. { 0x0aaf, 0x2025 },
  5717. { 0x0ab0, 0x2153 },
  5718. { 0x0ab1, 0x2154 },
  5719. { 0x0ab2, 0x2155 },
  5720. { 0x0ab3, 0x2156 },
  5721. { 0x0ab4, 0x2157 },
  5722. { 0x0ab5, 0x2158 },
  5723. { 0x0ab6, 0x2159 },
  5724. { 0x0ab7, 0x215a },
  5725. { 0x0ab8, 0x2105 },
  5726. { 0x0abb, 0x2012 },
  5727. { 0x0abc, 0x2329 },
  5728. { 0x0abe, 0x232a },
  5729. { 0x0ac3, 0x215b },
  5730. { 0x0ac4, 0x215c },
  5731. { 0x0ac5, 0x215d },
  5732. { 0x0ac6, 0x215e },
  5733. { 0x0ac9, 0x2122 },
  5734. { 0x0aca, 0x2613 },
  5735. { 0x0acc, 0x25c1 },
  5736. { 0x0acd, 0x25b7 },
  5737. { 0x0ace, 0x25cb },
  5738. { 0x0acf, 0x25af },
  5739. { 0x0ad0, 0x2018 },
  5740. { 0x0ad1, 0x2019 },
  5741. { 0x0ad2, 0x201c },
  5742. { 0x0ad3, 0x201d },
  5743. { 0x0ad4, 0x211e },
  5744. { 0x0ad6, 0x2032 },
  5745. { 0x0ad7, 0x2033 },
  5746. { 0x0ad9, 0x271d },
  5747. { 0x0adb, 0x25ac },
  5748. { 0x0adc, 0x25c0 },
  5749. { 0x0add, 0x25b6 },
  5750. { 0x0ade, 0x25cf },
  5751. { 0x0adf, 0x25ae },
  5752. { 0x0ae0, 0x25e6 },
  5753. { 0x0ae1, 0x25ab },
  5754. { 0x0ae2, 0x25ad },
  5755. { 0x0ae3, 0x25b3 },
  5756. { 0x0ae4, 0x25bd },
  5757. { 0x0ae5, 0x2606 },
  5758. { 0x0ae6, 0x2022 },
  5759. { 0x0ae7, 0x25aa },
  5760. { 0x0ae8, 0x25b2 },
  5761. { 0x0ae9, 0x25bc },
  5762. { 0x0aea, 0x261c },
  5763. { 0x0aeb, 0x261e },
  5764. { 0x0aec, 0x2663 },
  5765. { 0x0aed, 0x2666 },
  5766. { 0x0aee, 0x2665 },
  5767. { 0x0af0, 0x2720 },
  5768. { 0x0af1, 0x2020 },
  5769. { 0x0af2, 0x2021 },
  5770. { 0x0af3, 0x2713 },
  5771. { 0x0af4, 0x2717 },
  5772. { 0x0af5, 0x266f },
  5773. { 0x0af6, 0x266d },
  5774. { 0x0af7, 0x2642 },
  5775. { 0x0af8, 0x2640 },
  5776. { 0x0af9, 0x260e },
  5777. { 0x0afa, 0x2315 },
  5778. { 0x0afb, 0x2117 },
  5779. { 0x0afc, 0x2038 },
  5780. { 0x0afd, 0x201a },
  5781. { 0x0afe, 0x201e },
  5782. { 0x0ba3, 0x003c },
  5783. { 0x0ba6, 0x003e },
  5784. { 0x0ba8, 0x2228 },
  5785. { 0x0ba9, 0x2227 },
  5786. { 0x0bc0, 0x00af },
  5787. { 0x0bc2, 0x22a5 },
  5788. { 0x0bc3, 0x2229 },
  5789. { 0x0bc4, 0x230a },
  5790. { 0x0bc6, 0x005f },
  5791. { 0x0bca, 0x2218 },
  5792. { 0x0bcc, 0x2395 },
  5793. { 0x0bce, 0x22a4 },
  5794. { 0x0bcf, 0x25cb },
  5795. { 0x0bd3, 0x2308 },
  5796. { 0x0bd6, 0x222a },
  5797. { 0x0bd8, 0x2283 },
  5798. { 0x0bda, 0x2282 },
  5799. { 0x0bdc, 0x22a2 },
  5800. { 0x0bfc, 0x22a3 },
  5801. { 0x0cdf, 0x2017 },
  5802. { 0x0ce0, 0x05d0 },
  5803. { 0x0ce1, 0x05d1 },
  5804. { 0x0ce2, 0x05d2 },
  5805. { 0x0ce3, 0x05d3 },
  5806. { 0x0ce4, 0x05d4 },
  5807. { 0x0ce5, 0x05d5 },
  5808. { 0x0ce6, 0x05d6 },
  5809. { 0x0ce7, 0x05d7 },
  5810. { 0x0ce8, 0x05d8 },
  5811. { 0x0ce9, 0x05d9 },
  5812. { 0x0cea, 0x05da },
  5813. { 0x0ceb, 0x05db },
  5814. { 0x0cec, 0x05dc },
  5815. { 0x0ced, 0x05dd },
  5816. { 0x0cee, 0x05de },
  5817. { 0x0cef, 0x05df },
  5818. { 0x0cf0, 0x05e0 },
  5819. { 0x0cf1, 0x05e1 },
  5820. { 0x0cf2, 0x05e2 },
  5821. { 0x0cf3, 0x05e3 },
  5822. { 0x0cf4, 0x05e4 },
  5823. { 0x0cf5, 0x05e5 },
  5824. { 0x0cf6, 0x05e6 },
  5825. { 0x0cf7, 0x05e7 },
  5826. { 0x0cf8, 0x05e8 },
  5827. { 0x0cf9, 0x05e9 },
  5828. { 0x0cfa, 0x05ea },
  5829. { 0x0da1, 0x0e01 },
  5830. { 0x0da2, 0x0e02 },
  5831. { 0x0da3, 0x0e03 },
  5832. { 0x0da4, 0x0e04 },
  5833. { 0x0da5, 0x0e05 },
  5834. { 0x0da6, 0x0e06 },
  5835. { 0x0da7, 0x0e07 },
  5836. { 0x0da8, 0x0e08 },
  5837. { 0x0da9, 0x0e09 },
  5838. { 0x0daa, 0x0e0a },
  5839. { 0x0dab, 0x0e0b },
  5840. { 0x0dac, 0x0e0c },
  5841. { 0x0dad, 0x0e0d },
  5842. { 0x0dae, 0x0e0e },
  5843. { 0x0daf, 0x0e0f },
  5844. { 0x0db0, 0x0e10 },
  5845. { 0x0db1, 0x0e11 },
  5846. { 0x0db2, 0x0e12 },
  5847. { 0x0db3, 0x0e13 },
  5848. { 0x0db4, 0x0e14 },
  5849. { 0x0db5, 0x0e15 },
  5850. { 0x0db6, 0x0e16 },
  5851. { 0x0db7, 0x0e17 },
  5852. { 0x0db8, 0x0e18 },
  5853. { 0x0db9, 0x0e19 },
  5854. { 0x0dba, 0x0e1a },
  5855. { 0x0dbb, 0x0e1b },
  5856. { 0x0dbc, 0x0e1c },
  5857. { 0x0dbd, 0x0e1d },
  5858. { 0x0dbe, 0x0e1e },
  5859. { 0x0dbf, 0x0e1f },
  5860. { 0x0dc0, 0x0e20 },
  5861. { 0x0dc1, 0x0e21 },
  5862. { 0x0dc2, 0x0e22 },
  5863. { 0x0dc3, 0x0e23 },
  5864. { 0x0dc4, 0x0e24 },
  5865. { 0x0dc5, 0x0e25 },
  5866. { 0x0dc6, 0x0e26 },
  5867. { 0x0dc7, 0x0e27 },
  5868. { 0x0dc8, 0x0e28 },
  5869. { 0x0dc9, 0x0e29 },
  5870. { 0x0dca, 0x0e2a },
  5871. { 0x0dcb, 0x0e2b },
  5872. { 0x0dcc, 0x0e2c },
  5873. { 0x0dcd, 0x0e2d },
  5874. { 0x0dce, 0x0e2e },
  5875. { 0x0dcf, 0x0e2f },
  5876. { 0x0dd0, 0x0e30 },
  5877. { 0x0dd1, 0x0e31 },
  5878. { 0x0dd2, 0x0e32 },
  5879. { 0x0dd3, 0x0e33 },
  5880. { 0x0dd4, 0x0e34 },
  5881. { 0x0dd5, 0x0e35 },
  5882. { 0x0dd6, 0x0e36 },
  5883. { 0x0dd7, 0x0e37 },
  5884. { 0x0dd8, 0x0e38 },
  5885. { 0x0dd9, 0x0e39 },
  5886. { 0x0dda, 0x0e3a },
  5887. { 0x0ddf, 0x0e3f },
  5888. { 0x0de0, 0x0e40 },
  5889. { 0x0de1, 0x0e41 },
  5890. { 0x0de2, 0x0e42 },
  5891. { 0x0de3, 0x0e43 },
  5892. { 0x0de4, 0x0e44 },
  5893. { 0x0de5, 0x0e45 },
  5894. { 0x0de6, 0x0e46 },
  5895. { 0x0de7, 0x0e47 },
  5896. { 0x0de8, 0x0e48 },
  5897. { 0x0de9, 0x0e49 },
  5898. { 0x0dea, 0x0e4a },
  5899. { 0x0deb, 0x0e4b },
  5900. { 0x0dec, 0x0e4c },
  5901. { 0x0ded, 0x0e4d },
  5902. { 0x0df0, 0x0e50 },
  5903. { 0x0df1, 0x0e51 },
  5904. { 0x0df2, 0x0e52 },
  5905. { 0x0df3, 0x0e53 },
  5906. { 0x0df4, 0x0e54 },
  5907. { 0x0df5, 0x0e55 },
  5908. { 0x0df6, 0x0e56 },
  5909. { 0x0df7, 0x0e57 },
  5910. { 0x0df8, 0x0e58 },
  5911. { 0x0df9, 0x0e59 },
  5912. { 0x0ea1, 0x3131 },
  5913. { 0x0ea2, 0x3132 },
  5914. { 0x0ea3, 0x3133 },
  5915. { 0x0ea4, 0x3134 },
  5916. { 0x0ea5, 0x3135 },
  5917. { 0x0ea6, 0x3136 },
  5918. { 0x0ea7, 0x3137 },
  5919. { 0x0ea8, 0x3138 },
  5920. { 0x0ea9, 0x3139 },
  5921. { 0x0eaa, 0x313a },
  5922. { 0x0eab, 0x313b },
  5923. { 0x0eac, 0x313c },
  5924. { 0x0ead, 0x313d },
  5925. { 0x0eae, 0x313e },
  5926. { 0x0eaf, 0x313f },
  5927. { 0x0eb0, 0x3140 },
  5928. { 0x0eb1, 0x3141 },
  5929. { 0x0eb2, 0x3142 },
  5930. { 0x0eb3, 0x3143 },
  5931. { 0x0eb4, 0x3144 },
  5932. { 0x0eb5, 0x3145 },
  5933. { 0x0eb6, 0x3146 },
  5934. { 0x0eb7, 0x3147 },
  5935. { 0x0eb8, 0x3148 },
  5936. { 0x0eb9, 0x3149 },
  5937. { 0x0eba, 0x314a },
  5938. { 0x0ebb, 0x314b },
  5939. { 0x0ebc, 0x314c },
  5940. { 0x0ebd, 0x314d },
  5941. { 0x0ebe, 0x314e },
  5942. { 0x0ebf, 0x314f },
  5943. { 0x0ec0, 0x3150 },
  5944. { 0x0ec1, 0x3151 },
  5945. { 0x0ec2, 0x3152 },
  5946. { 0x0ec3, 0x3153 },
  5947. { 0x0ec4, 0x3154 },
  5948. { 0x0ec5, 0x3155 },
  5949. { 0x0ec6, 0x3156 },
  5950. { 0x0ec7, 0x3157 },
  5951. { 0x0ec8, 0x3158 },
  5952. { 0x0ec9, 0x3159 },
  5953. { 0x0eca, 0x315a },
  5954. { 0x0ecb, 0x315b },
  5955. { 0x0ecc, 0x315c },
  5956. { 0x0ecd, 0x315d },
  5957. { 0x0ece, 0x315e },
  5958. { 0x0ecf, 0x315f },
  5959. { 0x0ed0, 0x3160 },
  5960. { 0x0ed1, 0x3161 },
  5961. { 0x0ed2, 0x3162 },
  5962. { 0x0ed3, 0x3163 },
  5963. { 0x0ed4, 0x11a8 },
  5964. { 0x0ed5, 0x11a9 },
  5965. { 0x0ed6, 0x11aa },
  5966. { 0x0ed7, 0x11ab },
  5967. { 0x0ed8, 0x11ac },
  5968. { 0x0ed9, 0x11ad },
  5969. { 0x0eda, 0x11ae },
  5970. { 0x0edb, 0x11af },
  5971. { 0x0edc, 0x11b0 },
  5972. { 0x0edd, 0x11b1 },
  5973. { 0x0ede, 0x11b2 },
  5974. { 0x0edf, 0x11b3 },
  5975. { 0x0ee0, 0x11b4 },
  5976. { 0x0ee1, 0x11b5 },
  5977. { 0x0ee2, 0x11b6 },
  5978. { 0x0ee3, 0x11b7 },
  5979. { 0x0ee4, 0x11b8 },
  5980. { 0x0ee5, 0x11b9 },
  5981. { 0x0ee6, 0x11ba },
  5982. { 0x0ee7, 0x11bb },
  5983. { 0x0ee8, 0x11bc },
  5984. { 0x0ee9, 0x11bd },
  5985. { 0x0eea, 0x11be },
  5986. { 0x0eeb, 0x11bf },
  5987. { 0x0eec, 0x11c0 },
  5988. { 0x0eed, 0x11c1 },
  5989. { 0x0eee, 0x11c2 },
  5990. { 0x0eef, 0x316d },
  5991. { 0x0ef0, 0x3171 },
  5992. { 0x0ef1, 0x3178 },
  5993. { 0x0ef2, 0x317f },
  5994. { 0x0ef3, 0x3181 },
  5995. { 0x0ef4, 0x3184 },
  5996. { 0x0ef5, 0x3186 },
  5997. { 0x0ef6, 0x318d },
  5998. { 0x0ef7, 0x318e },
  5999. { 0x0ef8, 0x11eb },
  6000. { 0x0ef9, 0x11f0 },
  6001. { 0x0efa, 0x11f9 },
  6002. { 0x0eff, 0x20a9 },
  6003. { 0x13a4, 0x20ac },
  6004. { 0x13bc, 0x0152 },
  6005. { 0x13bd, 0x0153 },
  6006. { 0x13be, 0x0178 },
  6007. { 0x20ac, 0x20ac },
  6008. { 0xfe50, '`' },
  6009. { 0xfe51, 0x00b4 },
  6010. { 0xfe52, '^' },
  6011. { 0xfe53, '~' },
  6012. { 0xfe54, 0x00af },
  6013. { 0xfe55, 0x02d8 },
  6014. { 0xfe56, 0x02d9 },
  6015. { 0xfe57, 0x00a8 },
  6016. { 0xfe58, 0x02da },
  6017. { 0xfe59, 0x02dd },
  6018. { 0xfe5a, 0x02c7 },
  6019. { 0xfe5b, 0x00b8 },
  6020. { 0xfe5c, 0x02db },
  6021. { 0xfe5d, 0x037a },
  6022. { 0xfe5e, 0x309b },
  6023. { 0xfe5f, 0x309c },
  6024. { 0xfe63, '/' },
  6025. { 0xfe64, 0x02bc },
  6026. { 0xfe65, 0x02bd },
  6027. { 0xfe66, 0x02f5 },
  6028. { 0xfe67, 0x02f3 },
  6029. { 0xfe68, 0x02cd },
  6030. { 0xfe69, 0xa788 },
  6031. { 0xfe6a, 0x02f7 },
  6032. { 0xfe6e, ',' },
  6033. { 0xfe6f, 0x00a4 },
  6034. { 0xfe80, 'a' }, /* XK_dead_a */
  6035. { 0xfe81, 'A' }, /* XK_dead_A */
  6036. { 0xfe82, 'e' }, /* XK_dead_e */
  6037. { 0xfe83, 'E' }, /* XK_dead_E */
  6038. { 0xfe84, 'i' }, /* XK_dead_i */
  6039. { 0xfe85, 'I' }, /* XK_dead_I */
  6040. { 0xfe86, 'o' }, /* XK_dead_o */
  6041. { 0xfe87, 'O' }, /* XK_dead_O */
  6042. { 0xfe88, 'u' }, /* XK_dead_u */
  6043. { 0xfe89, 'U' }, /* XK_dead_U */
  6044. { 0xfe8a, 0x0259 },
  6045. { 0xfe8b, 0x018f },
  6046. { 0xfe8c, 0x00b5 },
  6047. { 0xfe90, '_' },
  6048. { 0xfe91, 0x02c8 },
  6049. { 0xfe92, 0x02cc },
  6050. { 0xff80 /*XKB_KEY_KP_Space*/, ' ' },
  6051. { 0xff95 /*XKB_KEY_KP_7*/, 0x0037 },
  6052. { 0xff96 /*XKB_KEY_KP_4*/, 0x0034 },
  6053. { 0xff97 /*XKB_KEY_KP_8*/, 0x0038 },
  6054. { 0xff98 /*XKB_KEY_KP_6*/, 0x0036 },
  6055. { 0xff99 /*XKB_KEY_KP_2*/, 0x0032 },
  6056. { 0xff9a /*XKB_KEY_KP_9*/, 0x0039 },
  6057. { 0xff9b /*XKB_KEY_KP_3*/, 0x0033 },
  6058. { 0xff9c /*XKB_KEY_KP_1*/, 0x0031 },
  6059. { 0xff9d /*XKB_KEY_KP_5*/, 0x0035 },
  6060. { 0xff9e /*XKB_KEY_KP_0*/, 0x0030 },
  6061. { 0xffaa /*XKB_KEY_KP_Multiply*/, '*' },
  6062. { 0xffab /*XKB_KEY_KP_Add*/, '+' },
  6063. { 0xffac /*XKB_KEY_KP_Separator*/, ',' },
  6064. { 0xffad /*XKB_KEY_KP_Subtract*/, '-' },
  6065. { 0xffae /*XKB_KEY_KP_Decimal*/, '.' },
  6066. { 0xffaf /*XKB_KEY_KP_Divide*/, '/' },
  6067. { 0xffb0 /*XKB_KEY_KP_0*/, 0x0030 },
  6068. { 0xffb1 /*XKB_KEY_KP_1*/, 0x0031 },
  6069. { 0xffb2 /*XKB_KEY_KP_2*/, 0x0032 },
  6070. { 0xffb3 /*XKB_KEY_KP_3*/, 0x0033 },
  6071. { 0xffb4 /*XKB_KEY_KP_4*/, 0x0034 },
  6072. { 0xffb5 /*XKB_KEY_KP_5*/, 0x0035 },
  6073. { 0xffb6 /*XKB_KEY_KP_6*/, 0x0036 },
  6074. { 0xffb7 /*XKB_KEY_KP_7*/, 0x0037 },
  6075. { 0xffb8 /*XKB_KEY_KP_8*/, 0x0038 },
  6076. { 0xffb9 /*XKB_KEY_KP_9*/, 0x0039 },
  6077. { 0xffbd /*XKB_KEY_KP_Equal*/, '=' }
  6078. };
  6079. _SOKOL_PRIVATE int _sapp_x11_error_handler(Display* display, XErrorEvent* event) {
  6080. _SOKOL_UNUSED(display);
  6081. _sapp_x11_error_code = event->error_code;
  6082. return 0;
  6083. }
  6084. _SOKOL_PRIVATE void _sapp_x11_grab_error_handler(void) {
  6085. _sapp_x11_error_code = Success;
  6086. XSetErrorHandler(_sapp_x11_error_handler);
  6087. }
  6088. _SOKOL_PRIVATE void _sapp_x11_release_error_handler(void) {
  6089. XSync(_sapp_x11_display, False);
  6090. XSetErrorHandler(NULL);
  6091. }
  6092. _SOKOL_PRIVATE void _sapp_x11_init_extensions(void) {
  6093. _sapp_x11_UTF8_STRING = XInternAtom(_sapp_x11_display, "UTF8_STRING", False);
  6094. _sapp_x11_WM_PROTOCOLS = XInternAtom(_sapp_x11_display, "WM_PROTOCOLS", False);
  6095. _sapp_x11_WM_DELETE_WINDOW = XInternAtom(_sapp_x11_display, "WM_DELETE_WINDOW", False);
  6096. _sapp_x11_WM_STATE = XInternAtom(_sapp_x11_display, "WM_STATE", False);
  6097. _sapp_x11_NET_WM_NAME = XInternAtom(_sapp_x11_display, "_NET_WM_NAME", False);
  6098. _sapp_x11_NET_WM_ICON_NAME = XInternAtom(_sapp_x11_display, "_NET_WM_ICON_NAME", False);
  6099. }
  6100. _SOKOL_PRIVATE void _sapp_x11_query_system_dpi(void) {
  6101. /* from GLFW:
  6102. NOTE: Default to the display-wide DPI as we don't currently have a policy
  6103. for which monitor a window is considered to be on
  6104. _sapp_x11_dpi = DisplayWidth(_sapp_x11_display, _sapp_x11_screen) *
  6105. 25.4f / DisplayWidthMM(_sapp_x11_display, _sapp_x11_screen);
  6106. NOTE: Basing the scale on Xft.dpi where available should provide the most
  6107. consistent user experience (matches Qt, Gtk, etc), although not
  6108. always the most accurate one
  6109. */
  6110. char* rms = XResourceManagerString(_sapp_x11_display);
  6111. if (rms) {
  6112. XrmDatabase db = XrmGetStringDatabase(rms);
  6113. if (db) {
  6114. XrmValue value;
  6115. char* type = NULL;
  6116. if (XrmGetResource(db, "Xft.dpi", "Xft.Dpi", &type, &value)) {
  6117. if (type && strcmp(type, "String") == 0) {
  6118. _sapp_x11_dpi = atof(value.addr);
  6119. }
  6120. }
  6121. XrmDestroyDatabase(db);
  6122. }
  6123. }
  6124. }
  6125. _SOKOL_PRIVATE bool _sapp_glx_has_ext(const char* ext, const char* extensions) {
  6126. SOKOL_ASSERT(ext);
  6127. const char* start = extensions;
  6128. while (true) {
  6129. const char* where = strstr(start, ext);
  6130. if (!where) {
  6131. return false;
  6132. }
  6133. const char* terminator = where + strlen(ext);
  6134. if ((where == start) || (*(where - 1) == ' ')) {
  6135. if (*terminator == ' ' || *terminator == '\0') {
  6136. break;
  6137. }
  6138. }
  6139. start = terminator;
  6140. }
  6141. return true;
  6142. }
  6143. _SOKOL_PRIVATE bool _sapp_glx_extsupported(const char* ext, const char* extensions) {
  6144. if (extensions) {
  6145. return _sapp_glx_has_ext(ext, extensions);
  6146. }
  6147. else {
  6148. return false;
  6149. }
  6150. }
  6151. _SOKOL_PRIVATE void* _sapp_glx_getprocaddr(const char* procname)
  6152. {
  6153. if (_sapp_glx_GetProcAddress) {
  6154. return (void*) _sapp_glx_GetProcAddress((const GLubyte*) procname);
  6155. }
  6156. else if (_sapp_glx_GetProcAddressARB) {
  6157. return (void*) _sapp_glx_GetProcAddressARB((const GLubyte*) procname);
  6158. }
  6159. else {
  6160. return dlsym(_sapp_glx_libgl, procname);
  6161. }
  6162. }
  6163. _SOKOL_PRIVATE void _sapp_glx_init() {
  6164. const char* sonames[] = { "libGL.so.1", "libGL.so", 0 };
  6165. for (int i = 0; sonames[i]; i++) {
  6166. _sapp_glx_libgl = dlopen(sonames[i], RTLD_LAZY|RTLD_GLOBAL);
  6167. if (_sapp_glx_libgl) {
  6168. break;
  6169. }
  6170. }
  6171. if (!_sapp_glx_libgl) {
  6172. _sapp_fail("GLX: failed to load libGL");
  6173. }
  6174. _sapp_glx_GetFBConfigs = (PFNGLXGETFBCONFIGSPROC) dlsym(_sapp_glx_libgl, "glXGetFBConfigs");
  6175. _sapp_glx_GetFBConfigAttrib = (PFNGLXGETFBCONFIGATTRIBPROC) dlsym(_sapp_glx_libgl, "glXGetFBConfigAttrib");
  6176. _sapp_glx_GetClientString = (PFNGLXGETCLIENTSTRINGPROC) dlsym(_sapp_glx_libgl, "glXGetClientString");
  6177. _sapp_glx_QueryExtension = (PFNGLXQUERYEXTENSIONPROC) dlsym(_sapp_glx_libgl, "glXQueryExtension");
  6178. _sapp_glx_QueryVersion = (PFNGLXQUERYVERSIONPROC) dlsym(_sapp_glx_libgl, "glXQueryVersion");
  6179. _sapp_glx_DestroyContext = (PFNGLXDESTROYCONTEXTPROC) dlsym(_sapp_glx_libgl, "glXDestroyContext");
  6180. _sapp_glx_MakeCurrent = (PFNGLXMAKECURRENTPROC) dlsym(_sapp_glx_libgl, "glXMakeCurrent");
  6181. _sapp_glx_SwapBuffers = (PFNGLXSWAPBUFFERSPROC) dlsym(_sapp_glx_libgl, "glXSwapBuffers");
  6182. _sapp_glx_QueryExtensionsString = (PFNGLXQUERYEXTENSIONSSTRINGPROC) dlsym(_sapp_glx_libgl, "glXQueryExtensionsString");
  6183. _sapp_glx_CreateNewContext = (PFNGLXCREATENEWCONTEXTPROC) dlsym(_sapp_glx_libgl, "glXCreateNewContext");
  6184. _sapp_glx_CreateWindow = (PFNGLXCREATEWINDOWPROC) dlsym(_sapp_glx_libgl, "glXCreateWindow");
  6185. _sapp_glx_DestroyWindow = (PFNGLXDESTROYWINDOWPROC) dlsym(_sapp_glx_libgl, "glXDestroyWindow");
  6186. _sapp_glx_GetProcAddress = (PFNGLXGETPROCADDRESSPROC) dlsym(_sapp_glx_libgl, "glXGetProcAddress");
  6187. _sapp_glx_GetProcAddressARB = (PFNGLXGETPROCADDRESSPROC) dlsym(_sapp_glx_libgl, "glXGetProcAddressARB");
  6188. _sapp_glx_GetVisualFromFBConfig = (PFNGLXGETVISUALFROMFBCONFIGPROC) dlsym(_sapp_glx_libgl, "glXGetVisualFromFBConfig");
  6189. if (!_sapp_glx_GetFBConfigs ||
  6190. !_sapp_glx_GetFBConfigAttrib ||
  6191. !_sapp_glx_GetClientString ||
  6192. !_sapp_glx_QueryExtension ||
  6193. !_sapp_glx_QueryVersion ||
  6194. !_sapp_glx_DestroyContext ||
  6195. !_sapp_glx_MakeCurrent ||
  6196. !_sapp_glx_SwapBuffers ||
  6197. !_sapp_glx_QueryExtensionsString ||
  6198. !_sapp_glx_CreateNewContext ||
  6199. !_sapp_glx_CreateWindow ||
  6200. !_sapp_glx_DestroyWindow ||
  6201. !_sapp_glx_GetProcAddress ||
  6202. !_sapp_glx_GetProcAddressARB ||
  6203. !_sapp_glx_GetVisualFromFBConfig)
  6204. {
  6205. _sapp_fail("GLX: failed to load required entry points");
  6206. }
  6207. if (!_sapp_glx_QueryExtension(_sapp_x11_display,
  6208. &_sapp_glx_errorbase,
  6209. &_sapp_glx_eventbase))
  6210. {
  6211. _sapp_fail("GLX: GLX extension not found");
  6212. }
  6213. if (!_sapp_glx_QueryVersion(_sapp_x11_display, &_sapp_glx_major, &_sapp_glx_minor)) {
  6214. _sapp_fail("GLX: Failed to query GLX version");
  6215. }
  6216. if (_sapp_glx_major == 1 && _sapp_glx_minor < 3) {
  6217. _sapp_fail("GLX: GLX version 1.3 is required");
  6218. }
  6219. const char* exts = _sapp_glx_QueryExtensionsString(_sapp_x11_display, _sapp_x11_screen);
  6220. if (_sapp_glx_extsupported("GLX_EXT_swap_control", exts)) {
  6221. _sapp_glx_SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) _sapp_glx_getprocaddr("glXSwapIntervalEXT");
  6222. _sapp_glx_EXT_swap_control = 0 != _sapp_glx_SwapIntervalEXT;
  6223. }
  6224. if (_sapp_glx_extsupported("GLX_MESA_swap_control", exts)) {
  6225. _sapp_glx_SwapIntervalMESA = (PFNGLXSWAPINTERVALMESAPROC) _sapp_glx_getprocaddr("glXSwapIntervalMESA");
  6226. _sapp_glx_MESA_swap_control = 0 != _sapp_glx_SwapIntervalMESA;
  6227. }
  6228. _sapp_glx_ARB_multisample = _sapp_glx_extsupported("GLX_ARB_multisample", exts);
  6229. _sapp_glx_ARB_framebuffer_sRGB = _sapp_glx_extsupported("GLX_ARB_framebuffer_sRGB", exts);
  6230. _sapp_glx_EXT_framebuffer_sRGB = _sapp_glx_extsupported("GLX_EXT_framebuffer_sRGB", exts);
  6231. if (_sapp_glx_extsupported("GLX_ARB_create_context", exts)) {
  6232. _sapp_glx_CreateContextAttribsARB = (PFNGLXCREATECONTEXTATTRIBSARBPROC) _sapp_glx_getprocaddr("glXCreateContextAttribsARB");
  6233. _sapp_glx_ARB_create_context = 0 != _sapp_glx_CreateContextAttribsARB;
  6234. }
  6235. _sapp_glx_ARB_create_context_profile = _sapp_glx_extsupported("GLX_ARB_create_context_profile", exts);
  6236. }
  6237. _SOKOL_PRIVATE int _sapp_glx_attrib(GLXFBConfig fbconfig, int attrib) {
  6238. int value;
  6239. _sapp_glx_GetFBConfigAttrib(_sapp_x11_display, fbconfig, attrib, &value);
  6240. return value;
  6241. }
  6242. _SOKOL_PRIVATE GLXFBConfig _sapp_glx_choosefbconfig() {
  6243. GLXFBConfig* native_configs;
  6244. _sapp_gl_fbconfig* usable_configs;
  6245. const _sapp_gl_fbconfig* closest;
  6246. int i, native_count, usable_count;
  6247. const char* vendor;
  6248. bool trust_window_bit = true;
  6249. /* HACK: This is a (hopefully temporary) workaround for Chromium
  6250. (VirtualBox GL) not setting the window bit on any GLXFBConfigs
  6251. */
  6252. vendor = _sapp_glx_GetClientString(_sapp_x11_display, GLX_VENDOR);
  6253. if (vendor && strcmp(vendor, "Chromium") == 0) {
  6254. trust_window_bit = false;
  6255. }
  6256. native_configs = _sapp_glx_GetFBConfigs(_sapp_x11_display, _sapp_x11_screen, &native_count);
  6257. if (!native_configs || !native_count) {
  6258. _sapp_fail("GLX: No GLXFBConfigs returned");
  6259. }
  6260. usable_configs = (_sapp_gl_fbconfig*) SOKOL_CALLOC(native_count, sizeof(_sapp_gl_fbconfig));
  6261. usable_count = 0;
  6262. for (i = 0; i < native_count; i++) {
  6263. const GLXFBConfig n = native_configs[i];
  6264. _sapp_gl_fbconfig* u = usable_configs + usable_count;
  6265. _sapp_gl_init_fbconfig(u);
  6266. /* Only consider RGBA GLXFBConfigs */
  6267. if (0 == (_sapp_glx_attrib(n, GLX_RENDER_TYPE) & GLX_RGBA_BIT)) {
  6268. continue;
  6269. }
  6270. /* Only consider window GLXFBConfigs */
  6271. if (0 == (_sapp_glx_attrib(n, GLX_DRAWABLE_TYPE) & GLX_WINDOW_BIT)) {
  6272. if (trust_window_bit) {
  6273. continue;
  6274. }
  6275. }
  6276. u->red_bits = _sapp_glx_attrib(n, GLX_RED_SIZE);
  6277. u->green_bits = _sapp_glx_attrib(n, GLX_GREEN_SIZE);
  6278. u->blue_bits = _sapp_glx_attrib(n, GLX_BLUE_SIZE);
  6279. u->alpha_bits = _sapp_glx_attrib(n, GLX_ALPHA_SIZE);
  6280. u->depth_bits = _sapp_glx_attrib(n, GLX_DEPTH_SIZE);
  6281. u->stencil_bits = _sapp_glx_attrib(n, GLX_STENCIL_SIZE);
  6282. if (_sapp_glx_attrib(n, GLX_DOUBLEBUFFER)) {
  6283. u->doublebuffer = true;
  6284. }
  6285. if (_sapp_glx_ARB_multisample) {
  6286. u->samples = _sapp_glx_attrib(n, GLX_SAMPLES);
  6287. }
  6288. u->handle = (uintptr_t) n;
  6289. usable_count++;
  6290. }
  6291. _sapp_gl_fbconfig desired;
  6292. _sapp_gl_init_fbconfig(&desired);
  6293. desired.red_bits = 8;
  6294. desired.green_bits = 8;
  6295. desired.blue_bits = 8;
  6296. desired.alpha_bits = 8;
  6297. desired.depth_bits = 24;
  6298. desired.stencil_bits = 8;
  6299. desired.doublebuffer = true;
  6300. desired.samples = _sapp.sample_count > 1 ? _sapp.sample_count : 0;
  6301. closest = _sapp_gl_choose_fbconfig(&desired, usable_configs, usable_count);
  6302. GLXFBConfig result = 0;
  6303. if (closest) {
  6304. result = (GLXFBConfig) closest->handle;
  6305. }
  6306. XFree(native_configs);
  6307. SOKOL_FREE(usable_configs);
  6308. return result;
  6309. }
  6310. _SOKOL_PRIVATE void _sapp_glx_choose_visual(Visual** visual, int* depth) {
  6311. GLXFBConfig native = _sapp_glx_choosefbconfig();
  6312. if (0 == native) {
  6313. _sapp_fail("GLX: Failed to find a suitable GLXFBConfig");
  6314. }
  6315. XVisualInfo* result = _sapp_glx_GetVisualFromFBConfig(_sapp_x11_display, native);
  6316. if (!result) {
  6317. _sapp_fail("GLX: Failed to retrieve Visual for GLXFBConfig");
  6318. }
  6319. *visual = result->visual;
  6320. *depth = result->depth;
  6321. XFree(result);
  6322. }
  6323. _SOKOL_PRIVATE void _sapp_glx_create_context(void) {
  6324. GLXFBConfig native = _sapp_glx_choosefbconfig();
  6325. if (0 == native){
  6326. _sapp_fail("GLX: Failed to find a suitable GLXFBConfig (2)");
  6327. }
  6328. if (!(_sapp_glx_ARB_create_context && _sapp_glx_ARB_create_context_profile)) {
  6329. _sapp_fail("GLX: ARB_create_context and ARB_create_context_profile required");
  6330. }
  6331. _sapp_x11_grab_error_handler();
  6332. const int attribs[] = {
  6333. GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
  6334. GLX_CONTEXT_MINOR_VERSION_ARB, 3,
  6335. GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
  6336. GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
  6337. 0, 0
  6338. };
  6339. _sapp_glx_ctx = _sapp_glx_CreateContextAttribsARB(_sapp_x11_display, native, NULL, True, attribs);
  6340. if (!_sapp_glx_ctx) {
  6341. _sapp_fail("GLX: failed to create GL context");
  6342. }
  6343. _sapp_x11_release_error_handler();
  6344. _sapp_glx_window = _sapp_glx_CreateWindow(_sapp_x11_display, native, _sapp_x11_window, NULL);
  6345. if (!_sapp_glx_window) {
  6346. _sapp_fail("GLX: failed to create window");
  6347. }
  6348. }
  6349. _SOKOL_PRIVATE void _sapp_glx_destroy_context(void) {
  6350. if (_sapp_glx_window) {
  6351. _sapp_glx_DestroyWindow(_sapp_x11_display, _sapp_glx_window);
  6352. _sapp_glx_window = 0;
  6353. }
  6354. if (_sapp_glx_ctx) {
  6355. _sapp_glx_DestroyContext(_sapp_x11_display, _sapp_glx_ctx);
  6356. _sapp_glx_ctx = 0;
  6357. }
  6358. }
  6359. _SOKOL_PRIVATE void _sapp_glx_make_current(void) {
  6360. _sapp_glx_MakeCurrent(_sapp_x11_display, _sapp_glx_window, _sapp_glx_ctx);
  6361. }
  6362. _SOKOL_PRIVATE void _sapp_glx_swap_buffers(void) {
  6363. _sapp_glx_SwapBuffers(_sapp_x11_display, _sapp_glx_window);
  6364. }
  6365. _SOKOL_PRIVATE void _sapp_glx_swapinterval(int interval) {
  6366. _sapp_glx_make_current();
  6367. if (_sapp_glx_EXT_swap_control) {
  6368. _sapp_glx_SwapIntervalEXT(_sapp_x11_display, _sapp_glx_window, interval);
  6369. }
  6370. else if (_sapp_glx_MESA_swap_control) {
  6371. _sapp_glx_SwapIntervalMESA(interval);
  6372. }
  6373. }
  6374. _SOKOL_PRIVATE void _sapp_x11_update_window_title(void) {
  6375. Xutf8SetWMProperties(_sapp_x11_display,
  6376. _sapp_x11_window,
  6377. _sapp.window_title, _sapp.window_title,
  6378. NULL, 0, NULL, NULL, NULL);
  6379. XChangeProperty(_sapp_x11_display, _sapp_x11_window,
  6380. _sapp_x11_NET_WM_NAME, _sapp_x11_UTF8_STRING, 8,
  6381. PropModeReplace,
  6382. (unsigned char*)_sapp.window_title,
  6383. strlen(_sapp.window_title));
  6384. XChangeProperty(_sapp_x11_display, _sapp_x11_window,
  6385. _sapp_x11_NET_WM_ICON_NAME, _sapp_x11_UTF8_STRING, 8,
  6386. PropModeReplace,
  6387. (unsigned char*)_sapp.window_title,
  6388. strlen(_sapp.window_title));
  6389. XFlush(_sapp_x11_display);
  6390. }
  6391. _SOKOL_PRIVATE void _sapp_x11_query_window_size(void) {
  6392. XWindowAttributes attribs;
  6393. XGetWindowAttributes(_sapp_x11_display, _sapp_x11_window, &attribs);
  6394. _sapp.window_width = attribs.width;
  6395. _sapp.window_height = attribs.height;
  6396. _sapp.framebuffer_width = _sapp.window_width;
  6397. _sapp.framebuffer_height = _sapp.framebuffer_height;
  6398. }
  6399. _SOKOL_PRIVATE void _sapp_x11_create_window(Visual* visual, int depth) {
  6400. _sapp_x11_colormap = XCreateColormap(_sapp_x11_display, _sapp_x11_root, visual, AllocNone);
  6401. XSetWindowAttributes wa;
  6402. memset(&wa, 0, sizeof(wa));
  6403. const uint32_t wamask = CWBorderPixel | CWColormap | CWEventMask;
  6404. wa.colormap = _sapp_x11_colormap;
  6405. wa.border_pixel = 0;
  6406. wa.event_mask = StructureNotifyMask | KeyPressMask | KeyReleaseMask |
  6407. PointerMotionMask | ButtonPressMask | ButtonReleaseMask |
  6408. ExposureMask | FocusChangeMask | VisibilityChangeMask |
  6409. EnterWindowMask | LeaveWindowMask | PropertyChangeMask;
  6410. _sapp_x11_grab_error_handler();
  6411. _sapp_x11_window = XCreateWindow(_sapp_x11_display,
  6412. _sapp_x11_root,
  6413. 0, 0,
  6414. _sapp.window_width,
  6415. _sapp.window_height,
  6416. 0, /* border width */
  6417. depth, /* color depth */
  6418. InputOutput,
  6419. visual,
  6420. wamask,
  6421. &wa);
  6422. _sapp_x11_release_error_handler();
  6423. if (!_sapp_x11_window) {
  6424. _sapp_fail("X11: Failed to create window");
  6425. }
  6426. Atom protocols[] = {
  6427. _sapp_x11_WM_DELETE_WINDOW
  6428. };
  6429. XSetWMProtocols(_sapp_x11_display, _sapp_x11_window, protocols, 1);
  6430. XSizeHints* hints = XAllocSizeHints();
  6431. hints->flags |= PWinGravity;
  6432. hints->win_gravity = StaticGravity;
  6433. XSetWMNormalHints(_sapp_x11_display, _sapp_x11_window, hints);
  6434. XFree(hints);
  6435. _sapp_x11_update_window_title();
  6436. _sapp_x11_query_window_size();
  6437. }
  6438. _SOKOL_PRIVATE void _sapp_x11_destroy_window(void) {
  6439. if (_sapp_x11_window) {
  6440. XUnmapWindow(_sapp_x11_display, _sapp_x11_window);
  6441. XDestroyWindow(_sapp_x11_display, _sapp_x11_window);
  6442. _sapp_x11_window = 0;
  6443. }
  6444. if (_sapp_x11_colormap) {
  6445. XFreeColormap(_sapp_x11_display, _sapp_x11_colormap);
  6446. _sapp_x11_colormap = 0;
  6447. }
  6448. XFlush(_sapp_x11_display);
  6449. }
  6450. _SOKOL_PRIVATE bool _sapp_x11_window_visible(void) {
  6451. XWindowAttributes wa;
  6452. XGetWindowAttributes(_sapp_x11_display, _sapp_x11_window, &wa);
  6453. return wa.map_state == IsViewable;
  6454. }
  6455. _SOKOL_PRIVATE void _sapp_x11_show_window(void) {
  6456. if (!_sapp_x11_window_visible()) {
  6457. XMapWindow(_sapp_x11_display, _sapp_x11_window);
  6458. XRaiseWindow(_sapp_x11_display, _sapp_x11_window);
  6459. XFlush(_sapp_x11_display);
  6460. }
  6461. }
  6462. _SOKOL_PRIVATE void _sapp_x11_hide_window(void) {
  6463. XUnmapWindow(_sapp_x11_display, _sapp_x11_window);
  6464. XFlush(_sapp_x11_display);
  6465. }
  6466. _SOKOL_PRIVATE unsigned long _sapp_x11_get_window_property(Atom property, Atom type, unsigned char** value) {
  6467. Atom actualType;
  6468. int actualFormat;
  6469. unsigned long itemCount, bytesAfter;
  6470. XGetWindowProperty(_sapp_x11_display,
  6471. _sapp_x11_window,
  6472. property,
  6473. 0,
  6474. LONG_MAX,
  6475. False,
  6476. type,
  6477. &actualType,
  6478. &actualFormat,
  6479. &itemCount,
  6480. &bytesAfter,
  6481. value);
  6482. return itemCount;
  6483. }
  6484. _SOKOL_PRIVATE int _sapp_x11_get_window_state(void) {
  6485. int result = WithdrawnState;
  6486. struct {
  6487. CARD32 state;
  6488. Window icon;
  6489. } *state = NULL;
  6490. if (_sapp_x11_get_window_property(_sapp_x11_WM_STATE, _sapp_x11_WM_STATE, (unsigned char**)&state) >= 2) {
  6491. result = state->state;
  6492. }
  6493. if (state) {
  6494. XFree(state);
  6495. }
  6496. return result;
  6497. }
  6498. _SOKOL_PRIVATE uint32_t _sapp_x11_mod(int x11_mods) {
  6499. uint32_t mods = 0;
  6500. if (x11_mods & ShiftMask) {
  6501. mods |= SAPP_MODIFIER_SHIFT;
  6502. }
  6503. if (x11_mods & ControlMask) {
  6504. mods |= SAPP_MODIFIER_CTRL;
  6505. }
  6506. if (x11_mods & Mod1Mask) {
  6507. mods |= SAPP_MODIFIER_ALT;
  6508. }
  6509. if (x11_mods & Mod4Mask) {
  6510. mods |= SAPP_MODIFIER_SUPER;
  6511. }
  6512. return mods;
  6513. }
  6514. _SOKOL_PRIVATE void _sapp_x11_app_event(sapp_event_type type) {
  6515. if (_sapp_events_enabled()) {
  6516. _sapp_init_event(type);
  6517. _sapp_call_event(&_sapp.event);
  6518. }
  6519. }
  6520. _SOKOL_PRIVATE sapp_mousebutton _sapp_x11_translate_button(const XEvent* event) {
  6521. switch (event->xbutton.button) {
  6522. case Button1: return SAPP_MOUSEBUTTON_LEFT;
  6523. case Button2: return SAPP_MOUSEBUTTON_MIDDLE;
  6524. case Button3: return SAPP_MOUSEBUTTON_RIGHT;
  6525. default: return SAPP_MOUSEBUTTON_INVALID;
  6526. }
  6527. }
  6528. _SOKOL_PRIVATE void _sapp_x11_mouse_event(sapp_event_type type, sapp_mousebutton btn, uint32_t mods) {
  6529. if (_sapp_events_enabled()) {
  6530. _sapp_init_event(type);
  6531. _sapp.event.mouse_button = btn;
  6532. _sapp.event.modifiers = mods;
  6533. _sapp.event.mouse_x = _sapp.mouse_x;
  6534. _sapp.event.mouse_y = _sapp.mouse_y;
  6535. _sapp_call_event(&_sapp.event);
  6536. }
  6537. }
  6538. _SOKOL_PRIVATE void _sapp_x11_scroll_event(float x, float y, uint32_t mods) {
  6539. if (_sapp_events_enabled()) {
  6540. _sapp_init_event(SAPP_EVENTTYPE_MOUSE_SCROLL);
  6541. _sapp.event.modifiers = mods;
  6542. _sapp.event.scroll_x = x;
  6543. _sapp.event.scroll_y = y;
  6544. _sapp_call_event(&_sapp.event);
  6545. }
  6546. }
  6547. _SOKOL_PRIVATE void _sapp_x11_key_event(sapp_event_type type, sapp_keycode key, bool repeat, uint32_t mods) {
  6548. if (_sapp_events_enabled()) {
  6549. _sapp_init_event(type);
  6550. _sapp.event.key_code = key;
  6551. _sapp.event.key_repeat = repeat;
  6552. _sapp.event.modifiers = mods;
  6553. _sapp_call_event(&_sapp.event);
  6554. /* check if a CLIPBOARD_PASTED event must be sent too */
  6555. if (_sapp.clipboard_enabled &&
  6556. (type == SAPP_EVENTTYPE_KEY_DOWN) &&
  6557. (_sapp.event.modifiers == SAPP_MODIFIER_CTRL) &&
  6558. (_sapp.event.key_code == SAPP_KEYCODE_V))
  6559. {
  6560. _sapp_init_event(SAPP_EVENTTYPE_CLIPBOARD_PASTED);
  6561. _sapp_call_event(&_sapp.event);
  6562. }
  6563. }
  6564. }
  6565. _SOKOL_PRIVATE void _sapp_x11_char_event(uint32_t chr, bool repeat, uint32_t mods) {
  6566. if (_sapp_events_enabled()) {
  6567. _sapp_init_event(SAPP_EVENTTYPE_CHAR);
  6568. _sapp.event.char_code = chr;
  6569. _sapp.event.key_repeat = repeat;
  6570. _sapp.event.modifiers = mods;
  6571. _sapp_call_event(&_sapp.event);
  6572. }
  6573. }
  6574. _SOKOL_PRIVATE sapp_keycode _sapp_x11_translate_key(int scancode) {
  6575. int dummy;
  6576. KeySym* keysyms = XGetKeyboardMapping(_sapp_x11_display, scancode, 1, &dummy);
  6577. SOKOL_ASSERT(keysyms);
  6578. KeySym keysym = keysyms[0];
  6579. XFree(keysyms);
  6580. switch (keysym) {
  6581. case XK_Escape: return SAPP_KEYCODE_ESCAPE;
  6582. case XK_Tab: return SAPP_KEYCODE_TAB;
  6583. case XK_Shift_L: return SAPP_KEYCODE_LEFT_SHIFT;
  6584. case XK_Shift_R: return SAPP_KEYCODE_RIGHT_SHIFT;
  6585. case XK_Control_L: return SAPP_KEYCODE_LEFT_CONTROL;
  6586. case XK_Control_R: return SAPP_KEYCODE_RIGHT_CONTROL;
  6587. case XK_Meta_L:
  6588. case XK_Alt_L: return SAPP_KEYCODE_LEFT_ALT;
  6589. case XK_Mode_switch: /* Mapped to Alt_R on many keyboards */
  6590. case XK_ISO_Level3_Shift: /* AltGr on at least some machines */
  6591. case XK_Meta_R:
  6592. case XK_Alt_R: return SAPP_KEYCODE_RIGHT_ALT;
  6593. case XK_Super_L: return SAPP_KEYCODE_LEFT_SUPER;
  6594. case XK_Super_R: return SAPP_KEYCODE_RIGHT_SUPER;
  6595. case XK_Menu: return SAPP_KEYCODE_MENU;
  6596. case XK_Num_Lock: return SAPP_KEYCODE_NUM_LOCK;
  6597. case XK_Caps_Lock: return SAPP_KEYCODE_CAPS_LOCK;
  6598. case XK_Print: return SAPP_KEYCODE_PRINT_SCREEN;
  6599. case XK_Scroll_Lock: return SAPP_KEYCODE_SCROLL_LOCK;
  6600. case XK_Pause: return SAPP_KEYCODE_PAUSE;
  6601. case XK_Delete: return SAPP_KEYCODE_DELETE;
  6602. case XK_BackSpace: return SAPP_KEYCODE_BACKSPACE;
  6603. case XK_Return: return SAPP_KEYCODE_ENTER;
  6604. case XK_Home: return SAPP_KEYCODE_HOME;
  6605. case XK_End: return SAPP_KEYCODE_END;
  6606. case XK_Page_Up: return SAPP_KEYCODE_PAGE_UP;
  6607. case XK_Page_Down: return SAPP_KEYCODE_PAGE_DOWN;
  6608. case XK_Insert: return SAPP_KEYCODE_INSERT;
  6609. case XK_Left: return SAPP_KEYCODE_LEFT;
  6610. case XK_Right: return SAPP_KEYCODE_RIGHT;
  6611. case XK_Down: return SAPP_KEYCODE_DOWN;
  6612. case XK_Up: return SAPP_KEYCODE_UP;
  6613. case XK_F1: return SAPP_KEYCODE_F1;
  6614. case XK_F2: return SAPP_KEYCODE_F2;
  6615. case XK_F3: return SAPP_KEYCODE_F3;
  6616. case XK_F4: return SAPP_KEYCODE_F4;
  6617. case XK_F5: return SAPP_KEYCODE_F5;
  6618. case XK_F6: return SAPP_KEYCODE_F6;
  6619. case XK_F7: return SAPP_KEYCODE_F7;
  6620. case XK_F8: return SAPP_KEYCODE_F8;
  6621. case XK_F9: return SAPP_KEYCODE_F9;
  6622. case XK_F10: return SAPP_KEYCODE_F10;
  6623. case XK_F11: return SAPP_KEYCODE_F11;
  6624. case XK_F12: return SAPP_KEYCODE_F12;
  6625. case XK_F13: return SAPP_KEYCODE_F13;
  6626. case XK_F14: return SAPP_KEYCODE_F14;
  6627. case XK_F15: return SAPP_KEYCODE_F15;
  6628. case XK_F16: return SAPP_KEYCODE_F16;
  6629. case XK_F17: return SAPP_KEYCODE_F17;
  6630. case XK_F18: return SAPP_KEYCODE_F18;
  6631. case XK_F19: return SAPP_KEYCODE_F19;
  6632. case XK_F20: return SAPP_KEYCODE_F20;
  6633. case XK_F21: return SAPP_KEYCODE_F21;
  6634. case XK_F22: return SAPP_KEYCODE_F22;
  6635. case XK_F23: return SAPP_KEYCODE_F23;
  6636. case XK_F24: return SAPP_KEYCODE_F24;
  6637. case XK_F25: return SAPP_KEYCODE_F25;
  6638. case XK_KP_Divide: return SAPP_KEYCODE_KP_DIVIDE;
  6639. case XK_KP_Multiply: return SAPP_KEYCODE_KP_MULTIPLY;
  6640. case XK_KP_Subtract: return SAPP_KEYCODE_KP_SUBTRACT;
  6641. case XK_KP_Add: return SAPP_KEYCODE_KP_ADD;
  6642. case XK_KP_Insert: return SAPP_KEYCODE_KP_0;
  6643. case XK_KP_End: return SAPP_KEYCODE_KP_1;
  6644. case XK_KP_Down: return SAPP_KEYCODE_KP_2;
  6645. case XK_KP_Page_Down: return SAPP_KEYCODE_KP_3;
  6646. case XK_KP_Left: return SAPP_KEYCODE_KP_4;
  6647. case XK_KP_Begin: return SAPP_KEYCODE_KP_5;
  6648. case XK_KP_Right: return SAPP_KEYCODE_KP_6;
  6649. case XK_KP_Home: return SAPP_KEYCODE_KP_7;
  6650. case XK_KP_Up: return SAPP_KEYCODE_KP_8;
  6651. case XK_KP_Page_Up: return SAPP_KEYCODE_KP_9;
  6652. case XK_KP_Delete: return SAPP_KEYCODE_KP_DECIMAL;
  6653. case XK_KP_Equal: return SAPP_KEYCODE_KP_EQUAL;
  6654. case XK_KP_Enter: return SAPP_KEYCODE_KP_ENTER;
  6655. case XK_a: return SAPP_KEYCODE_A;
  6656. case XK_b: return SAPP_KEYCODE_B;
  6657. case XK_c: return SAPP_KEYCODE_C;
  6658. case XK_d: return SAPP_KEYCODE_D;
  6659. case XK_e: return SAPP_KEYCODE_E;
  6660. case XK_f: return SAPP_KEYCODE_F;
  6661. case XK_g: return SAPP_KEYCODE_G;
  6662. case XK_h: return SAPP_KEYCODE_H;
  6663. case XK_i: return SAPP_KEYCODE_I;
  6664. case XK_j: return SAPP_KEYCODE_J;
  6665. case XK_k: return SAPP_KEYCODE_K;
  6666. case XK_l: return SAPP_KEYCODE_L;
  6667. case XK_m: return SAPP_KEYCODE_M;
  6668. case XK_n: return SAPP_KEYCODE_N;
  6669. case XK_o: return SAPP_KEYCODE_O;
  6670. case XK_p: return SAPP_KEYCODE_P;
  6671. case XK_q: return SAPP_KEYCODE_Q;
  6672. case XK_r: return SAPP_KEYCODE_R;
  6673. case XK_s: return SAPP_KEYCODE_S;
  6674. case XK_t: return SAPP_KEYCODE_T;
  6675. case XK_u: return SAPP_KEYCODE_U;
  6676. case XK_v: return SAPP_KEYCODE_V;
  6677. case XK_w: return SAPP_KEYCODE_W;
  6678. case XK_x: return SAPP_KEYCODE_X;
  6679. case XK_y: return SAPP_KEYCODE_Y;
  6680. case XK_z: return SAPP_KEYCODE_Z;
  6681. case XK_1: return SAPP_KEYCODE_1;
  6682. case XK_2: return SAPP_KEYCODE_2;
  6683. case XK_3: return SAPP_KEYCODE_3;
  6684. case XK_4: return SAPP_KEYCODE_4;
  6685. case XK_5: return SAPP_KEYCODE_5;
  6686. case XK_6: return SAPP_KEYCODE_6;
  6687. case XK_7: return SAPP_KEYCODE_7;
  6688. case XK_8: return SAPP_KEYCODE_8;
  6689. case XK_9: return SAPP_KEYCODE_9;
  6690. case XK_0: return SAPP_KEYCODE_0;
  6691. case XK_space: return SAPP_KEYCODE_SPACE;
  6692. case XK_minus: return SAPP_KEYCODE_MINUS;
  6693. case XK_equal: return SAPP_KEYCODE_EQUAL;
  6694. case XK_bracketleft: return SAPP_KEYCODE_LEFT_BRACKET;
  6695. case XK_bracketright: return SAPP_KEYCODE_RIGHT_BRACKET;
  6696. case XK_backslash: return SAPP_KEYCODE_BACKSLASH;
  6697. case XK_semicolon: return SAPP_KEYCODE_SEMICOLON;
  6698. case XK_apostrophe: return SAPP_KEYCODE_APOSTROPHE;
  6699. case XK_grave: return SAPP_KEYCODE_GRAVE_ACCENT;
  6700. case XK_comma: return SAPP_KEYCODE_COMMA;
  6701. case XK_period: return SAPP_KEYCODE_PERIOD;
  6702. case XK_slash: return SAPP_KEYCODE_SLASH;
  6703. case XK_less: return SAPP_KEYCODE_WORLD_1; /* At least in some layouts... */
  6704. default: return SAPP_KEYCODE_INVALID;
  6705. }
  6706. }
  6707. _SOKOL_PRIVATE int32_t _sapp_x11_keysym_to_unicode(KeySym keysym) {
  6708. int min = 0;
  6709. int max = sizeof(_sapp_x11_keysymtab) / sizeof(struct _sapp_x11_codepair) - 1;
  6710. int mid;
  6711. /* First check for Latin-1 characters (1:1 mapping) */
  6712. if ((keysym >= 0x0020 && keysym <= 0x007e) ||
  6713. (keysym >= 0x00a0 && keysym <= 0x00ff))
  6714. {
  6715. return keysym;
  6716. }
  6717. /* Also check for directly encoded 24-bit UCS characters */
  6718. if ((keysym & 0xff000000) == 0x01000000) {
  6719. return keysym & 0x00ffffff;
  6720. }
  6721. /* Binary search in table */
  6722. while (max >= min) {
  6723. mid = (min + max) / 2;
  6724. if (_sapp_x11_keysymtab[mid].keysym < keysym) {
  6725. min = mid + 1;
  6726. }
  6727. else if (_sapp_x11_keysymtab[mid].keysym > keysym) {
  6728. max = mid - 1;
  6729. }
  6730. else {
  6731. return _sapp_x11_keysymtab[mid].ucs;
  6732. }
  6733. }
  6734. /* No matching Unicode value found */
  6735. return -1;
  6736. }
  6737. // XLib manual says keycodes are in the range [8, 255] inclusive.
  6738. // https://tronche.com/gui/x/xlib/input/keyboard-encoding.html
  6739. static bool _sapp_x11_keycodes[256];
  6740. _SOKOL_PRIVATE void _sapp_x11_process_event(XEvent* event) {
  6741. switch (event->type) {
  6742. case KeyPress:
  6743. {
  6744. int keycode = event->xkey.keycode;
  6745. const sapp_keycode key = _sapp_x11_translate_key(keycode);
  6746. bool repeat = _sapp_x11_keycodes[keycode & 0xFF];
  6747. _sapp_x11_keycodes[keycode & 0xFF] = true;
  6748. const uint32_t mods = _sapp_x11_mod(event->xkey.state);
  6749. if (key != SAPP_KEYCODE_INVALID) {
  6750. _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_DOWN, key, repeat, mods);
  6751. }
  6752. KeySym keysym;
  6753. XLookupString(&event->xkey, NULL, 0, &keysym, NULL);
  6754. int32_t chr = _sapp_x11_keysym_to_unicode(keysym);
  6755. if (chr > 0) {
  6756. _sapp_x11_char_event((uint32_t)chr, repeat, mods);
  6757. }
  6758. }
  6759. break;
  6760. case KeyRelease:
  6761. {
  6762. int keycode = event->xkey.keycode;
  6763. const sapp_keycode key = _sapp_x11_translate_key(keycode);
  6764. _sapp_x11_keycodes[keycode & 0xFF] = false;
  6765. if (key != SAPP_KEYCODE_INVALID) {
  6766. const uint32_t mods = _sapp_x11_mod(event->xkey.state);
  6767. _sapp_x11_key_event(SAPP_EVENTTYPE_KEY_UP, key, false, mods);
  6768. }
  6769. }
  6770. break;
  6771. case ButtonPress:
  6772. {
  6773. const sapp_mousebutton btn = _sapp_x11_translate_button(event);
  6774. const uint32_t mods = _sapp_x11_mod(event->xbutton.state);
  6775. if (btn != SAPP_MOUSEBUTTON_INVALID) {
  6776. _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_DOWN, btn, mods);
  6777. }
  6778. else {
  6779. /* might be a scroll event */
  6780. switch (event->xbutton.button) {
  6781. case 4: _sapp_x11_scroll_event(0.0f, 1.0f, mods); break;
  6782. case 5: _sapp_x11_scroll_event(0.0f, -1.0f, mods); break;
  6783. case 6: _sapp_x11_scroll_event(1.0f, 0.0f, mods); break;
  6784. case 7: _sapp_x11_scroll_event(-1.0f, 0.0f, mods); break;
  6785. }
  6786. }
  6787. }
  6788. break;
  6789. case ButtonRelease:
  6790. {
  6791. const sapp_mousebutton btn = _sapp_x11_translate_button(event);
  6792. if (btn != SAPP_MOUSEBUTTON_INVALID) {
  6793. _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_UP, btn, _sapp_x11_mod(event->xbutton.state));
  6794. }
  6795. }
  6796. break;
  6797. case EnterNotify:
  6798. _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_ENTER, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xcrossing.state));
  6799. break;
  6800. case LeaveNotify:
  6801. _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_LEAVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xcrossing.state));
  6802. break;
  6803. case MotionNotify:
  6804. _sapp.mouse_x = event->xmotion.x;
  6805. _sapp.mouse_y = event->xmotion.y;
  6806. _sapp_x11_mouse_event(SAPP_EVENTTYPE_MOUSE_MOVE, SAPP_MOUSEBUTTON_INVALID, _sapp_x11_mod(event->xmotion.state));
  6807. break;
  6808. case ConfigureNotify:
  6809. if ((event->xconfigure.width != _sapp.window_width) || (event->xconfigure.height != _sapp.window_height)) {
  6810. _sapp.window_width = event->xconfigure.width;
  6811. _sapp.window_height = event->xconfigure.height;
  6812. _sapp.framebuffer_width = _sapp.window_width;
  6813. _sapp.framebuffer_height = _sapp.window_height;
  6814. _sapp_x11_app_event(SAPP_EVENTTYPE_RESIZED);
  6815. }
  6816. break;
  6817. case PropertyNotify:
  6818. if (event->xproperty.state == PropertyNewValue) {
  6819. if (event->xproperty.atom == _sapp_x11_WM_STATE) {
  6820. const int state = _sapp_x11_get_window_state();
  6821. if (state != _sapp_x11_window_state) {
  6822. _sapp_x11_window_state = state;
  6823. if (state == IconicState) {
  6824. _sapp_x11_app_event(SAPP_EVENTTYPE_ICONIFIED);
  6825. }
  6826. else if (state == NormalState) {
  6827. _sapp_x11_app_event(SAPP_EVENTTYPE_RESTORED);
  6828. }
  6829. }
  6830. }
  6831. }
  6832. break;
  6833. case ClientMessage:
  6834. if (event->xclient.message_type == _sapp_x11_WM_PROTOCOLS) {
  6835. const Atom protocol = event->xclient.data.l[0];
  6836. if (protocol == _sapp_x11_WM_DELETE_WINDOW) {
  6837. _sapp.quit_requested = true;
  6838. }
  6839. }
  6840. break;
  6841. case DestroyNotify:
  6842. break;
  6843. }
  6844. }
  6845. _SOKOL_PRIVATE void _sapp_run(const sapp_desc* desc) {
  6846. _sapp_init_state(desc);
  6847. _sapp_x11_window_state = NormalState;
  6848. XInitThreads();
  6849. XrmInitialize();
  6850. _sapp_x11_display = XOpenDisplay(NULL);
  6851. if (!_sapp_x11_display) {
  6852. _sapp_fail("XOpenDisplay() failed!\n");
  6853. }
  6854. _sapp_x11_screen = DefaultScreen(_sapp_x11_display);
  6855. _sapp_x11_root = DefaultRootWindow(_sapp_x11_display);
  6856. XkbSetDetectableAutoRepeat(_sapp_x11_display, true, NULL);
  6857. _sapp_x11_query_system_dpi();
  6858. _sapp.dpi_scale = _sapp_x11_dpi / 96.0f;
  6859. _sapp_x11_init_extensions();
  6860. _sapp_glx_init();
  6861. Visual* visual = 0;
  6862. int depth = 0;
  6863. _sapp_glx_choose_visual(&visual, &depth);
  6864. _sapp_x11_create_window(visual, depth);
  6865. _sapp_glx_create_context();
  6866. _sapp.valid = true;
  6867. _sapp_x11_show_window();
  6868. _sapp_glx_swapinterval(_sapp.swap_interval);
  6869. XFlush(_sapp_x11_display);
  6870. while (!_sapp.quit_ordered) {
  6871. _sapp_glx_make_current();
  6872. int count = XPending(_sapp_x11_display);
  6873. while (count--) {
  6874. XEvent event;
  6875. XNextEvent(_sapp_x11_display, &event);
  6876. _sapp_x11_process_event(&event);
  6877. }
  6878. _sapp_frame();
  6879. _sapp_glx_swap_buffers();
  6880. XFlush(_sapp_x11_display);
  6881. /* handle quit-requested, either from window or from sapp_request_quit() */
  6882. if (_sapp.quit_requested && !_sapp.quit_ordered) {
  6883. /* give user code a chance to intervene */
  6884. _sapp_x11_app_event(SAPP_EVENTTYPE_QUIT_REQUESTED);
  6885. /* if user code hasn't intervened, quit the app */
  6886. if (_sapp.quit_requested) {
  6887. _sapp.quit_ordered = true;
  6888. }
  6889. }
  6890. }
  6891. _sapp_call_cleanup();
  6892. _sapp_glx_destroy_context();
  6893. _sapp_x11_destroy_window();
  6894. XCloseDisplay(_sapp_x11_display);
  6895. _sapp_discard_state();
  6896. }
  6897. #if !defined(SOKOL_NO_ENTRY)
  6898. int main(int argc, char* argv[]) {
  6899. sapp_desc desc = sokol_main(argc, argv);
  6900. _sapp_run(&desc);
  6901. return 0;
  6902. }
  6903. #endif /* SOKOL_NO_ENTRY */
  6904. #endif /* LINUX */
  6905. /*== PUBLIC API FUNCTIONS ====================================================*/
  6906. #if defined(SOKOL_NO_ENTRY)
  6907. SOKOL_API_IMPL int sapp_run(const sapp_desc* desc) {
  6908. SOKOL_ASSERT(desc);
  6909. _sapp_run(desc);
  6910. return 0;
  6911. }
  6912. /* this is just a stub so the linker doesn't complain */
  6913. sapp_desc sokol_main(int argc, char* argv[]) {
  6914. _SOKOL_UNUSED(argc);
  6915. _SOKOL_UNUSED(argv);
  6916. sapp_desc desc;
  6917. memset(&desc, 0, sizeof(desc));
  6918. return desc;
  6919. }
  6920. #else
  6921. /* likewise, in normal mode, sapp_run() is just an empty stub */
  6922. SOKOL_API_IMPL int sapp_run(const sapp_desc* desc) {
  6923. _SOKOL_UNUSED(desc);
  6924. return 0;
  6925. }
  6926. #endif
  6927. SOKOL_API_IMPL bool sapp_isvalid(void) {
  6928. return _sapp.valid;
  6929. }
  6930. SOKOL_API_IMPL void* sapp_userdata(void) {
  6931. return _sapp.desc.user_data;
  6932. }
  6933. SOKOL_API_IMPL sapp_desc sapp_query_desc(void) {
  6934. return _sapp.desc;
  6935. }
  6936. SOKOL_API_IMPL uint64_t sapp_frame_count(void) {
  6937. return _sapp.frame_count;
  6938. }
  6939. SOKOL_API_IMPL int sapp_width(void) {
  6940. return (_sapp.framebuffer_width > 0) ? _sapp.framebuffer_width : 1;
  6941. }
  6942. SOKOL_API_IMPL int sapp_height(void) {
  6943. return (_sapp.framebuffer_height > 0) ? _sapp.framebuffer_height : 1;
  6944. }
  6945. SOKOL_API_IMPL bool sapp_high_dpi(void) {
  6946. return _sapp.desc.high_dpi && (_sapp.dpi_scale > 1.5f);
  6947. }
  6948. SOKOL_API_IMPL float sapp_dpi_scale(void) {
  6949. return _sapp.dpi_scale;
  6950. }
  6951. SOKOL_API_IMPL bool sapp_gles2(void) {
  6952. return _sapp.gles2_fallback;
  6953. }
  6954. SOKOL_API_IMPL void sapp_show_keyboard(bool shown) {
  6955. #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
  6956. _sapp_ios_show_keyboard(shown);
  6957. #elif defined(__EMSCRIPTEN__)
  6958. _sapp_emsc_show_keyboard(shown);
  6959. #elif defined(__ANDROID__)
  6960. _sapp_android_show_keyboard(shown);
  6961. #else
  6962. _SOKOL_UNUSED(shown);
  6963. #endif
  6964. }
  6965. SOKOL_API_IMPL bool sapp_keyboard_shown(void) {
  6966. return _sapp.onscreen_keyboard_shown;
  6967. }
  6968. SOKOL_API_IMPL void sapp_show_mouse(bool shown) {
  6969. #if defined(_WIN32)
  6970. _sapp_win32_show_mouse(shown);
  6971. #else
  6972. _SOKOL_UNUSED(shown);
  6973. #endif
  6974. }
  6975. SOKOL_API_IMPL bool sapp_mouse_shown(void) {
  6976. #if defined(_WIN32)
  6977. return _sapp_win32_mouse_shown();
  6978. #else
  6979. return false;
  6980. #endif
  6981. }
  6982. SOKOL_API_IMPL void sapp_request_quit(void) {
  6983. _sapp.quit_requested = true;
  6984. }
  6985. SOKOL_API_IMPL void sapp_cancel_quit(void) {
  6986. _sapp.quit_requested = false;
  6987. }
  6988. SOKOL_API_IMPL void sapp_quit(void) {
  6989. _sapp.quit_ordered = true;
  6990. }
  6991. SOKOL_API_IMPL void sapp_consume_event(void) {
  6992. _sapp.event_consumed = true;
  6993. }
  6994. /* NOTE: on HTML5, sapp_set_clipboard_string() must be called from within event handler! */
  6995. SOKOL_API_IMPL void sapp_set_clipboard_string(const char* str) {
  6996. if (!_sapp.clipboard_enabled) {
  6997. return;
  6998. }
  6999. SOKOL_ASSERT(str);
  7000. #if defined(__APPLE__) && defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
  7001. _sapp_macos_set_clipboard_string(str);
  7002. #elif defined(__EMSCRIPTEN__)
  7003. _sapp_emsc_set_clipboard_string(str);
  7004. #elif defined(_WIN32)
  7005. _sapp_win32_set_clipboard_string(str);
  7006. #else
  7007. /* not implemented */
  7008. #endif
  7009. _sapp_strcpy(str, _sapp.clipboard, _sapp.clipboard_size);
  7010. }
  7011. SOKOL_API_IMPL const char* sapp_get_clipboard_string(void) {
  7012. if (!_sapp.clipboard_enabled) {
  7013. return "";
  7014. }
  7015. #if defined(__APPLE__) && defined(TARGET_OS_IPHONE) && !TARGET_OS_IPHONE
  7016. return _sapp_macos_get_clipboard_string();
  7017. #elif defined(__EMSCRIPTEN__)
  7018. return _sapp.clipboard;
  7019. #elif defined(_WIN32)
  7020. return _sapp_win32_get_clipboard_string();
  7021. #else
  7022. /* not implemented */
  7023. return _sapp.clipboard;
  7024. #endif
  7025. }
  7026. SOKOL_API_IMPL const void* sapp_metal_get_device(void) {
  7027. SOKOL_ASSERT(_sapp.valid);
  7028. #if defined(SOKOL_METAL)
  7029. const void* obj = (__bridge const void*) _sapp_mtl_device_obj;
  7030. SOKOL_ASSERT(obj);
  7031. return obj;
  7032. #else
  7033. return 0;
  7034. #endif
  7035. }
  7036. SOKOL_API_IMPL const void* sapp_metal_get_renderpass_descriptor(void) {
  7037. SOKOL_ASSERT(_sapp.valid);
  7038. #if defined(SOKOL_METAL)
  7039. const void* obj = (__bridge const void*) [_sapp_view_obj currentRenderPassDescriptor];
  7040. SOKOL_ASSERT(obj);
  7041. return obj;
  7042. #else
  7043. return 0;
  7044. #endif
  7045. }
  7046. SOKOL_API_IMPL const void* sapp_metal_get_drawable(void) {
  7047. SOKOL_ASSERT(_sapp.valid);
  7048. #if defined(SOKOL_METAL)
  7049. const void* obj = (__bridge const void*) [_sapp_view_obj currentDrawable];
  7050. SOKOL_ASSERT(obj);
  7051. return obj;
  7052. #else
  7053. return 0;
  7054. #endif
  7055. }
  7056. SOKOL_API_IMPL const void* sapp_macos_get_window(void) {
  7057. #if defined(__APPLE__) && !TARGET_OS_IPHONE
  7058. const void* obj = (__bridge const void*) _sapp_macos_window_obj;
  7059. SOKOL_ASSERT(obj);
  7060. return obj;
  7061. #else
  7062. return 0;
  7063. #endif
  7064. }
  7065. SOKOL_API_IMPL const void* sapp_ios_get_window(void) {
  7066. #if defined(__APPLE__) && TARGET_OS_IPHONE
  7067. const void* obj = (__bridge const void*) _sapp_ios_window_obj;
  7068. SOKOL_ASSERT(obj);
  7069. return obj;
  7070. #else
  7071. return 0;
  7072. #endif
  7073. }
  7074. SOKOL_API_IMPL const void* sapp_d3d11_get_device(void) {
  7075. SOKOL_ASSERT(_sapp.valid);
  7076. #if defined(SOKOL_D3D11)
  7077. return _sapp_d3d11_device;
  7078. #else
  7079. return 0;
  7080. #endif
  7081. }
  7082. SOKOL_API_IMPL const void* sapp_d3d11_get_device_context(void) {
  7083. SOKOL_ASSERT(_sapp.valid);
  7084. #if defined(SOKOL_D3D11)
  7085. return _sapp_d3d11_device_context;
  7086. #else
  7087. return 0;
  7088. #endif
  7089. }
  7090. SOKOL_API_IMPL const void* sapp_d3d11_get_render_target_view(void) {
  7091. SOKOL_ASSERT(_sapp.valid);
  7092. #if defined(SOKOL_D3D11)
  7093. return _sapp_d3d11_rtv;
  7094. #else
  7095. return 0;
  7096. #endif
  7097. }
  7098. SOKOL_API_IMPL const void* sapp_d3d11_get_depth_stencil_view(void) {
  7099. SOKOL_ASSERT(_sapp.valid);
  7100. #if defined(SOKOL_D3D11)
  7101. return _sapp_d3d11_dsv;
  7102. #else
  7103. return 0;
  7104. #endif
  7105. }
  7106. SOKOL_API_IMPL const void* sapp_win32_get_hwnd(void) {
  7107. SOKOL_ASSERT(_sapp.valid);
  7108. #if defined(_WIN32)
  7109. return _sapp_win32_hwnd;
  7110. #else
  7111. return 0;
  7112. #endif
  7113. }
  7114. SOKOL_API_IMPL const void* sapp_android_get_native_activity(void) {
  7115. SOKOL_ASSERT(_sapp.valid);
  7116. #if defined(__ANDROID__)
  7117. return (void*)_sapp_android_state.activity;
  7118. #else
  7119. return 0;
  7120. #endif
  7121. }
  7122. SOKOL_API_IMPL void sapp_html5_ask_leave_site(bool ask) {
  7123. _sapp.html5_ask_leave_site = ask;
  7124. }
  7125. #undef _sapp_def
  7126. #ifdef _MSC_VER
  7127. #pragma warning(pop)
  7128. #endif
  7129. #endif /* SOKOL_IMPL */