WHELM Mac OS

broken image


An open letter to Peter Cohen

(e.g., MAC address, hostname, email address). Lax System and Network Administration— The SANS Institute identifies the most frequently-targeted OS, application and network components in its annual Top 20 list—but you could easily compile a list of common configuration errors that is twice as long and causes more security inci-dents. Tor is an encrypted anonymising network that makes it harder to intercept internet communications, or see where communications are coming from or going to. In order to use the WikiLeaks public submission system as detailed above you can download the Tor Browser Bundle, which is a Firefox-like browser available for Windows, Mac OS X and GNU/Linux and pre-configured to connect using the.

Dear Peter,

As you know, I once penned Macworld'sGame Room column. And, now blessed with that beat, you may be starting to feel the way I did once I passed the column along to Andy Ihnatko—if you ever see another computer game, it will be too soon. The once unrelenting joy of vaporizing one cootie after another became a terrible grind.

Having had nearly a decade-long break from the column, my interest in gaming has started to return. Sure, it's only been resurrected to the point where I've purchased the reissue of Return to Dark Castle and LittleWing's Monster Fair (so sue me, I've got a nostalgic streak and I'm still a sucker for pinball), but at least there's some spark.

What rekindled my once-dead romance with gaming may surprise you. It was my iPhone. I've jailbroken the thing since just about Day 1 and when I have a spare couple of minutes, it's not unusual to find me banging away on Mahjong 2.

I mention this game specifically because I noticed that the iTunes Store now offers updated versions of iPod games that were pulled from the Store's shelves because they weren't compatible with the 3G iPod nano and iPod classic. Among those games is Electronic Arts' Mahjong.

Given that I've had recent experience with the iPhone's version of the game, I thought I'd give the Apple-sanctioned Mahjong a spin (quite literally, thanks to the iPod's clickwheel). Having done so I was prompted to write to you because you, more than anyone I know, might have an informed answer to this question:

iPod gaming kind of sucks, right?

And I suggest that for these reasons:

  • An iPod's screen—even a 5G or iPod classic—is awfully small for someone who doesn't have 14-year-old eyes.
  • The clickwheel is great for quickly moving through lists but as a game controller, ick.
  • The eye candy on some of these things is nice enough, but try playing these games without sound (as you do with games on jailbroken phones). Maybe it's just me, but without the accompanying noise some of these games don't stand up very well.

I admit it, I was among those crying out for more iPod games, but having seen what's possible on the iPhone and iPod touch (also jailbroken)—larger screen, acceleration, touch-interface—it's hard for me to return to a 'traditional' iPod and gain much pleasure from spinning a wheel and clicking a button. And I have to think that it will be just as hard for those who own both an iPhone/iPod touch and a clickwheel iPod when third-party games come to the iPhone and touch this summer.

Will the iPhone 2.0 software and the games that will pour in with it spell the end for gaming on traditional iPods? You now bear the master's mantle, please set me straight.

Your friend and colleague,

Chris

Read Peter Cohen's response.

Un­til now, the Plat­form::Sdl2Ap­pli­ca­tion was the go-to so­lu­tion for mostplat­forms in­clud­ing the web and mo­bile. How­ev­er, not ev­ery­body needs all thefea­tures SDL pro­vides and, es­pe­cial­ly on Em­scripten, apart from sim­pli­fy­ingport­ing it doesn't re­al­ly add any­thing ex­tra on top. On the con­trary, thead­di­tion­al lay­er of trans­la­tion be­tween HTM­L5 and SDL APIs in­creas­es theex­e­cutable size and makes some fea­tures un­nec­es­sar­i­ly hard to ac­cess.

To solve that, the new Plat­form::Em­scripte­nAp­pli­ca­tion, con­trib­uted inmosra/mag­num#300 by @Squareys, is us­ing Em­scripten HTM­L5 APIsdi­rect­ly, open­ing new pos­si­bil­i­ties while mak­ing the code small­er and moreef­fi­cient.

'SDL2' vs SDL2

Since there's some con­fu­sion about SDL among Em­scripten users, let's clar­i­fythat first. Us­ing SDL in Em­scripten is ac­tu­al­ly pos­si­ble in two ways — theim­plic­it sup­port, im­ple­ment­ed in li­brary_s­dl.js,gives you a slight­ly strange hy­brid of SDL1 and SDL2 in a rel­a­tive­ly smallpack­age. Not all SDL2 APIs are present there, on the oth­er hand it has enoughfrom SDL2 to make it a vi­able al­ter­na­tive to the SDL2 ev­ery­one is used to. Thisis what Plat­form::Sdl2Ap­pli­ca­tion is us­ing.

The oth­er way is a 'full SDL2', avail­able if you pass -s USE_SDL=2 to thelink­er. Two years ago we tried to re­move all Em­scripten-spe­cif­ic work­aroundsfrom Plat­form::Sdl2Ap­pli­ca­tion by switch­ing to this full SDL2, butquick­ly re­al­ized it was a bad de­ci­sion — in to­tal it re­moved 30 lines ofcode, but caused the re­sult­ing code to be al­most 600 kB larg­er. The sizein­crease was so se­ri­ous that it didn't war­rant the very mi­nor im­prove­ments incode main­tain­abil­i­ty. For the record, the orig­i­nal pull re­quest is archived atmosra/mag­num#218.

The SDL-free Em­scripte­nAp­pli­ca­tion

All ap­pli­ca­tion im­ple­men­ta­tions in Mag­num strive for al­most full APIcom­pat­i­bil­i­ty, with the goal of mak­ing it pos­si­ble to use an im­ple­men­ta­tionop­ti­mal for cho­sen plat­form and use case. This was al­ready the case withPlat­form::GlfwAp­pli­ca­tion and Plat­form::Sdl2Ap­pli­ca­tion, whereswitch­ing from one to the oth­er is in 90% cas­es just a mat­ter of us­ing adif­fer­ent #include and pass­ing a dif­fer­ent com­po­nent to CMake'sfind_package().

The new Plat­form::Em­scripte­nAp­pli­ca­tion con­tin­ues in this fash­ion and weport­ed all ex­ist­ing ex­am­ples and tools that for­mer­ly usedPlat­form::Sdl2Ap­pli­ca­tion to it to en­sure it works in broad use cas­es.Apart from that, the new im­ple­men­ta­tion fix­es some of the long-stand­ing is­sueslike mis­cal­cu­lat­ed event co­or­di­nates on mo­bile web browsers or theDelete key leak­ing through text in­put events.

On­ly two wide­ly used APIs are miss­ing from it right now — thePlat­form::Sdl2Ap­pli­ca­tion::tick­Event() andPlat­form::Sdl2Ap­pli­ca­tion::setSwap­In­ter­val(). The for­mer will getadded to­geth­er with an equiv­a­lent in GLFW ap­pli­ca­tion, while the sec­ondwill be ex­posed dif­fer­ent­ly, al­low­ing to use the ex­tend­ed brows­er APIs.Right now it's enough to #ifdef around it, as browsers, un­likemost desk­top plat­forms, en­able VSync by de­fault.

Pow­er-ef­fi­cient idle be­hav­ior

Since the very be­gin­ning, all Mag­num ap­pli­ca­tion im­ple­men­ta­tions de­fault tore­draw­ing on­ly when need­ed in or­der to save pow­er — be­cause Mag­num is notjust for games that have to an­i­mate some­thing ev­ery frame, it doesn't makesense to use up all sys­tem re­sources by de­fault. While this is sim­ple toim­ple­ment ef­fi­cient­ly on desk­top apps where the ap­pli­ca­tion has the fullcon­trol over the main loop (and thus can block in­def­i­nite­ly wait­ing for anin­put event), it's hard­er in the call­back-based brows­er en­vi­ron­ment.

The orig­i­nal Plat­form::Sdl2Ap­pli­ca­tion makes use ofem­scripten_set_­main_loop(),which pe­ri­od­i­cal­ly calls win­dow.re­ques­tAni­ma­tion­Frame()in or­der to main­tain a steady frame rate. For apps that need to re­draw on­lywhen need­ed this means the call­back will be called 60 times per sec­ond on­ly tobe a no-op. While that's still sig­nif­i­cant­ly more ef­fi­cient than draw­ingev­ery­thing each time, it still means the brows­er has to wake up 60 times persec­ond to do noth­ing.

Whelm Mac Os Download

Plat­form::Em­scripte­nAp­pli­ca­tion in­stead makes use ofre­ques­tAni­ma­tion­Frame()di­rect­ly — the next an­i­ma­tion frame is im­plic­it­ly sched­uled, but can­celledagain af­ter the draw event if the app doesn't wish to re­draw im­me­di­ate­ly again.That takes the best of both worlds — re­draws are still VSync'd, but thebrows­er is not loop­ing need­less­ly if the app just wants to wait with a re­drawfor the next in­put event. To give you some num­bers, be­low is a ten-sec­ondout­put of Chrome's per­for­mance mon­i­tor com­par­ing SDL and Em­scripten appim­ple­men­ta­tion wait­ing for an in­put event. You can re­pro­duce this with theMag­num Play­er — no mat­ter how com­plexan­i­mat­ed scene you throw at it, if you pause the an­i­ma­tion it will use as muchCPU as a plain stat­ic text web page.

DPI aware­ness re­vis­it­ed

Ar­guably to sim­pli­fy port­ing, the Em­scripten SDL em­u­la­tion re­cal­cu­lates allin­put event co­or­di­nates to match frame­buffer pix­els. The ac­tu­al DPI scal­ing(or de­vice pix­el ra­tio) is then be­ing ex­posed through dpiS­cal­ing(),mak­ing it be­have the same as Lin­ux, Win­dows and An­droid on high-DPI screens. Incon­trast, HTM­L5 APIs be­have like mac­OS / iOS andPlat­form::Em­scripte­nAp­pli­ca­tion fol­lows that be­hav­ior —frame­buf­fer­Size()thus match­es de­vice pix­els while win­dow­Size()(to which all events are re­lat­ed) is small­er on HiD­PI sys­tems. For morein­for­ma­tion, check out the DPI aware­ness docs.

It's im­por­tant to note that even though dif­fer­ent plat­forms ex­pose DPIaware­ness in a dif­fer­ent way, Mag­num APIs are de­signed in a way that makesit pos­si­ble to have the same code be­have cor­rect­ly ev­ery­where. Thesep­a­ra­tion in­to dpiS­cal­ing(),frame­buf­fer­Size() andwin­dow­Size() prop­er­tiesis main­ly for a more fine-grained con­trol where need­ed.

Ex­e­cutable size sav­in­gs

Be­cause we didn't end up us­ing the heavy­weight 'full SDL2' in the first place,the dif­fer­ence in ex­e­cutable size is noth­ing ex­treme — in to­tal, in a Re­leaseWe­bAssem­bly build, the JS size got small­er by about 20 kB, while the WASM filestays rough­ly the same.

Min­i­mal run­time, or brain surgery with a chain­saw

On the oth­er hand, since the new ap­pli­ca­tion doesn't use any of the emscripten_set_main_loop() APIs from library_browser.js, it makes ita good can­di­date for play­ing with the rel­a­tive­ly re­centMIN­I­MAL_RUN­TIME fea­ture of Em­scripten.Now, while Mag­num is mov­ing in the right di­rec­tion, it's not yet in a statewhere this would 'just work'. Sup­port­ing MINIMAL_RUNTIME re­quires ei­thermov­ing fast and break­ing lots of things or have the APIs slow­ly evolve in­to astate that makes it pos­si­ble. Be­cause re­li­able back­wards com­pat­i­bil­i­ty andpain­less up­grade path is a valu­able as­set in our port­fo­lio, we chose thelat­ter — it will even­tu­al­ly hap­pen, but not right now. An­oth­er rea­son is thatwhile Mag­num it­self can be high­ly op­ti­mized to be com­pat­i­ble with min­i­malrun­time, the usu­al ap­pli­ca­tion code is not able to sat­is­fy those re­quire­mentswith­out re­mov­ing and rewrit­ing most third-par­ty de­pen­den­cies.

Mac os download

That be­ing said, why not spend one af­ter­noon with a chain­saw and tryde­mol­ish­ing the code to see what could come out? It's how­ev­er im­por­tant tonote that MINIMAL_RUNTIME is still a very fresh fea­ture and thus it's verylike­ly that a lot of code will sim­ply not work with it. All the dis­cov­eredprob­lems are list­ed be­low be­cause at this point there are no re­sults at allwhen googling them, so hope­ful­ly this helps oth­er peo­ple stuck in sim­i­larplaces:

Mac Os Download

  • std::getenv() or the environ vari­able (used byUtil­i­ty::Ar­gu­ments) re­sults in writeAsciiToMemory() be­ingcalled, which is right now ex­plic­it­ly dis­abledfor min­i­mal run­time (and thus you ei­ther get a fail­ure at run­time or theClo­sure Com­pil­er com­plain­ing about these names be­ing un­de­fined). SinceEm­scripten's en­vi­ron­ment is just a bunch of hard­cod­ed val­ues and Mag­num isus­ing Node.js APIs to get the re­al val­ues for com­mand-line apps any­way,so­lu­tion is to sim­ply not use those func­tions.
  • Right now, Mag­num is us­ing C++ iostreams on three iso­lat­ed places(Util­i­ty::De­bug be­ing the most prom­i­nent) and those us­es aregrad­u­al­ly be­ing phased off. On Em­scripten, us­ing any­thing that evenre­mote­ly touch­es them will make the back­end emit calls tollvm_stacksave() andllvm_stackrestore(). The JavaScript im­ple­men­ta­tionsthen call stackSave() and stackRestore() which how­ev­er do notget pulled in in MINIMAL_RUNTIME, again re­sult­ing in ei­ther a run­timeer­ror ev­ery time you call in­to JS (so al­so allemscripten_set_mousedown_callback() func­tions) or when you use theClo­sure Com­pil­er. Af­ter wast­ing a few hours try­ing to con­vince Em­scriptento emit these two by adding _llvm_stacksave__deps:['$stackSave'] theul­ti­mate so­lu­tion was to kill ev­ery­thing stream-re­lat­ed. Con­sid­er­ingev­ery­one who's in­ter­est­ed in MINIMAL_RUNTIME prob­a­bly did that al­ready,it ex­plains why this is an­oth­er un­googleable er­ror.
  • If you use C++ streams, the gen­er­at­ed JS driv­er file con­tains a fullJavaScript im­ple­men­ta­tion of strftime() and the on­ly way to get ridof it is re­mov­ing all stream us­age as well. Grep your JS file for Monday— if it's there, you have a prob­lem.
  • JavaScript Em­scripten APIs like dynCall() or allocate() are notavail­able and putting them in­to ei­ther EXTRA_EXPORTED_RUNTIME_METHODSor RUNTIME_FUNCS_TO_IMPORT ei­ther didn't do any­thing or moved theer­ror in­to a dif­fer­ent place. For the for­mer it was pos­si­ble to work aroundit by di­rect­ly call­ing one of its spe­cial­iza­tions (in that par­tic­u­lar casedynCall_ii()), the sec­ond re­sult­ed in a frus­trat­ed table­flip and therel­e­vant piece of code get­ting cut off.

Dodge the creeps redux mac os. Be­low is a break­down of var­i­ous op­ti­miza­tions on a min­i­mal ap­pli­ca­tion thatdoes just a frame­buffer clear, each step chop­ping an­oth­er bit off the to­taldown­load size. All sizes are un­com­pressed, built in Re­lease mode with -Oz,--llvm-lto 1 and --closure 1. Lat­er on in the process,Bloaty McBloat­Face ex­per­i­men­talWe­bAssem­bly sup­port was used to dis­cov­er what func­tions con­trib­ute the most to fi­nalcode size.

Whelm mac os catalina

That be­ing said, why not spend one af­ter­noon with a chain­saw and tryde­mol­ish­ing the code to see what could come out? It's how­ev­er im­por­tant tonote that MINIMAL_RUNTIME is still a very fresh fea­ture and thus it's verylike­ly that a lot of code will sim­ply not work with it. All the dis­cov­eredprob­lems are list­ed be­low be­cause at this point there are no re­sults at allwhen googling them, so hope­ful­ly this helps oth­er peo­ple stuck in sim­i­larplaces:

Mac Os Download

  • std::getenv() or the environ vari­able (used byUtil­i­ty::Ar­gu­ments) re­sults in writeAsciiToMemory() be­ingcalled, which is right now ex­plic­it­ly dis­abledfor min­i­mal run­time (and thus you ei­ther get a fail­ure at run­time or theClo­sure Com­pil­er com­plain­ing about these names be­ing un­de­fined). SinceEm­scripten's en­vi­ron­ment is just a bunch of hard­cod­ed val­ues and Mag­num isus­ing Node.js APIs to get the re­al val­ues for com­mand-line apps any­way,so­lu­tion is to sim­ply not use those func­tions.
  • Right now, Mag­num is us­ing C++ iostreams on three iso­lat­ed places(Util­i­ty::De­bug be­ing the most prom­i­nent) and those us­es aregrad­u­al­ly be­ing phased off. On Em­scripten, us­ing any­thing that evenre­mote­ly touch­es them will make the back­end emit calls tollvm_stacksave() andllvm_stackrestore(). The JavaScript im­ple­men­ta­tionsthen call stackSave() and stackRestore() which how­ev­er do notget pulled in in MINIMAL_RUNTIME, again re­sult­ing in ei­ther a run­timeer­ror ev­ery time you call in­to JS (so al­so allemscripten_set_mousedown_callback() func­tions) or when you use theClo­sure Com­pil­er. Af­ter wast­ing a few hours try­ing to con­vince Em­scriptento emit these two by adding _llvm_stacksave__deps:['$stackSave'] theul­ti­mate so­lu­tion was to kill ev­ery­thing stream-re­lat­ed. Con­sid­er­ingev­ery­one who's in­ter­est­ed in MINIMAL_RUNTIME prob­a­bly did that al­ready,it ex­plains why this is an­oth­er un­googleable er­ror.
  • If you use C++ streams, the gen­er­at­ed JS driv­er file con­tains a fullJavaScript im­ple­men­ta­tion of strftime() and the on­ly way to get ridof it is re­mov­ing all stream us­age as well. Grep your JS file for Monday— if it's there, you have a prob­lem.
  • JavaScript Em­scripten APIs like dynCall() or allocate() are notavail­able and putting them in­to ei­ther EXTRA_EXPORTED_RUNTIME_METHODSor RUNTIME_FUNCS_TO_IMPORT ei­ther didn't do any­thing or moved theer­ror in­to a dif­fer­ent place. For the for­mer it was pos­si­ble to work aroundit by di­rect­ly call­ing one of its spe­cial­iza­tions (in that par­tic­u­lar casedynCall_ii()), the sec­ond re­sult­ed in a frus­trat­ed table­flip and therel­e­vant piece of code get­ting cut off.

Dodge the creeps redux mac os. Be­low is a break­down of var­i­ous op­ti­miza­tions on a min­i­mal ap­pli­ca­tion thatdoes just a frame­buffer clear, each step chop­ping an­oth­er bit off the to­taldown­load size. All sizes are un­com­pressed, built in Re­lease mode with -Oz,--llvm-lto 1 and --closure 1. Lat­er on in the process,Bloaty McBloat­Face ex­per­i­men­talWe­bAssem­bly sup­port was used to dis­cov­er what func­tions con­trib­ute the most to fi­nalcode size.

Op­er­a­tionJS sizeWASM size
Ini­tial state52.1 kB226.3 kB
En­abling min­i­mal run­time 136.3 kB224.5 kB
Ad­di­tion­al slim­ming flags 235.7 kB224.5 kB
Dis­abling filesys­tem 319.4 kB224.5 kB
Chop­ping off all C++ stream us­age14.7 kB83.6 kB
En­abling COR­RADE_NO_ASSERT14.7 kB75.4 kB
Re­mov­ing a sin­gle use of std::sort()414.7 kB69.3 kB
Re­mov­ing one std::un­or­dered_map414.7 kB62.6 kB
Us­ing em­mal­loc in­stead of dl­mal­loc 514.7 kB56.3 kB
Re­mov­ing all printf() us­age 614.7 kB44 kB (es­ti­mate)

Mac Os Versions

1.
^-s MINIMAL_RUNTIME=2 -s ENVIRONMENT=web -lGL plus tem­po­rar­ilyen­abling al­so -s IGNORE_CLOSURE_COMPILER_ERRORS=1 in or­der to makeClo­sure Com­pil­er sur­vive un­de­fined vari­able er­rors due to iostreams andoth­er, men­tioned above
2.
^-s SUPPORT_ERRNO=0 -s GL_EMULATE_GLES_VERSION_STRING_FORMAT=0 -s GL_EXTENSIONS_IN_PREFIXED_FORMAT=0 -s GL_SUPPORT_AUTOMATIC_ENABLE_EXTENSIONS=0 -s GL_TRACK_ERRORS=0 -s DISABLE_DEPRECATED_FIND_EVENT_TARGET_BEHAVIOR=1— ba­si­cal­ly dis­abling what's en­abled by de­fault. In par­tic­u­lar, theGL_EXTENSIONS_IN_PREFIXED_FORMAT=0 is not sup­port­ed by Mag­num rightnow, caus­ing it to not re­port any ex­ten­sions, but that can be eas­i­ly fixed.The re­sult of dis­abling all these is … un­der­whelm­ing.
3.
^-s FILESYSTEM=0, makes Em­scripten not emit any filesys­tem-re­lat­edcode. Mag­num pro­vides filesys­tem ac­cess through var­i­ous APIs(Util­i­ty::Di­rec­to­ry, GL::Shad­er::addFile(),Trade::Ab­strac­tIm­porter::open­File(), …) and at the mo­ment there'sno pos­si­bil­i­ty to com­pile all these out, so this is a nu­cle­ar op­tion thatworks.
4.
^ abGL::Con­text us­es a std::sort() and astd::un­or­dered_map to check for ex­ten­sion pres­ence and print theirlist in the en­gine start­up log. It was fright­en­ing to see a re­moval of asin­gle std::sort() caus­ing a 10% drop in ex­e­cutable size — sinceWe­bGL has rough­ly two dozens ex­ten­sions (com­pared to > 200 on desk­top andES), maybe a space-ef­fi­cient al­ter­na­tive im­ple­men­ta­tion could be donefor this tar­get in­stead.
5.
^Doug Lea‘smal­loc() is a gen­er­al-pur­pose al­lo­ca­tor, used byglibc among oth­ers. It's very per­for­mant and a good choice for code thatdoes many small al­lo­ca­tions (std::un­or­dered_map, I'm look­ing atyou). The down­side is its larg­er size, and code do­ing few­er larg­eral­lo­ca­tions might want to use -s MALLOC=emmalloc in­stead. We don'tpre­tend Mag­num is at that state yet, but oth­er projectssucess­ful­ly switched to it, shav­ingmore bytes off the down­load size.
6.
^ Af­ter re­mov­ing all of the above, std::printf() in­ter­nals start­edap­pear­ing at the top of Bloaty's size re­port, to­talling at about 10% of theex­e­cutable size. Mag­num doesn't use it any­where di­rect­ly and all tran­si­tiveus­age of it was killed to­geth­er with iostreams; fur­ther dig­ging re­vealedthat it gets called from libc++'s abort_mes­sage(),for ex­am­ple when abort­ing due to a pure vir­tu­al func­tion call. In­de­pen­dentmea­sure­ment showed that std::printf() is around 12 kB of ad­di­tion­alcode com­pared to std::puts(), main­ly due to the in­her­ent com­plex­i­tyof float­ing-point string con­ver­sion. It's planned to use the muchsim­pler and small­er Ryū al­go­rithmfor Mag­num's std::printf() re­place­ment, ad­di­tion­al­ly en­sur­ing thatfloat-to-string con­ver­sions can be DCE-dwhen not used. We might be look­ing in­to patch­ing Em­scripten's libc++ to notuse the ex­pen­sive im­ple­men­ta­tion in its abort mes­sages.

While all of the above size re­duc­tions were done in a hack-and-slash man­ner,the fi­nal ex­e­cutable still ini­tial­izes and ex­e­cutes prop­er­ly, clear­ing theframe­buffer and re­act­ing to in­put events. For ref­er­ence, check out diffs ofthe chainsaw-surgery branch­es in cor­radeand mag­num.

The above is def­i­nite­ly not all that can be done — es­pe­cial­ly con­sid­er­ingthat re­mov­ing two us­es of se­mi-heavy STL APIs led to al­most 20% save in codesize, there are most prob­a­bly more of such low hang­ing fruits. The above taskswere added to mosra/mag­num#293 (if not there al­ready) and will getgrad­u­al­ly in­te­grat­ed in­to master.

Con­clu­sion

Bright times ahead! The new Plat­form::Em­scripte­nAp­pli­ca­tion is the firststep to tru­ly min­i­mal We­bAssem­bly builds and the above hints that it's pos­si­bleto have down­load sizes not too far from code care­ful­ly writ­ten in plain C.To give a fair com­par­i­son, the ba­sic frame­buffer clear sam­ple from@floooh‘s Sokol Sam­ples is 42kB in to­tal, while the above equiv­a­lent is rough­ly 59 kB. Us­ing C++(11), butnot overus­ing it — and that's just the be­gin­ning.

Ques­tions? Com­plaints? Share your opin­ion on so­cial net­works:Twit­ter,Red­dit r/cpp,r/We­bAssem­bly,Hack­er News



broken image