[video output=day530 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Writing Large PNGs and Supersampling Fonts" vod_platform=youtube id=6-nOuoehfd4 annotator=Miblo]
[0:00][Recap and set the stage for the day with a few words on asset metadata][:"asset system" :font :speech]
[4:19][Determine to address the "Support writing "large" PNGs" issue[ref
    site=GitHub
    page="HandmadeHero / cpp / Support writing \"large\" PNGs"
    url=https://github.com/HandmadeHero/cpp/issues/92]][:"asset system" :research]
[7:01][Run our :font exporter–extractor for 20px high glyphs][:admin :"asset system"]
[8:44][Run our :font exporter–extractor for 512px high glyphs to exhibit our bug][:admin :"asset system"]
[10:34][Set up to enable WritePNG() write out large images in multiple chunks][:"asset system" :font :research]
[12:51][Enable WritePNG() to write out multiple chunks[ref
    site=W3C
    page="Portable Network Graphics (PNG) Specification (Second Edition)"
    url=https://w3.org/TR/2003/REC-PNG-20031110/]][:"asset system" :"file format"]
[25:26][Consult the ZLIB spec to see where the ADLER32 checksum is supposed to go[ref
        site=IETF
        page="ZLIB Compressed Data Format Specification version 3.3"
        url=http://www.ietf.org/rfc/rfc1950.txt]][:"file format" :research]
[28:22][Continue to enable WritePNG() to handle multiple chunks, prepending rows with the filter value][:"asset system" :"file format"]
[36:59][Thoughts on a more succinct and maintainable specification of the ability to modify rarely modified values, e.g. PNG filter per row][:"file format" :speech]
[38:31][Continue to enable WritePNG() to process rows for multiple chunks][:"asset system" :"file format"]
[41:23][Enable WritePNG() to handle the ADLER32 checksum for multiple chunks, introducing BeginAdler32() and Adler32Append()][:"file format" :hashing]
[48:01][Step through WritePNG() to find that our B and Width fail to line up][:"asset system" :"file format" :run]
[50:11][Fix WritePNG() to correctly detect the end of row][:"asset system" :"file format"]
[50:41][Run hhfont to completion, and check out a glyph in GIMP to see no antialiasing][:admin :"asset system" :"file format" :font]
[52:15][Consult the documentation on CreateFontA() for its ANTIALIASED_QUALITY parameter[ref
        site="Windows Dev Center"
        page="CreateFontA function"
        url=https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-createfonta]][:font :"platform layer" :research]
[55:26][Enable ExtractFont() and LoadGlyphBitmap() to oversample our output glyphs[ref
        site="Windows Dev Center"
        page="CreateFontA function"
        url=https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-createfonta]][:font :rendering]
[1:11:27][Run our exporter–extractor to find that we produced corrupted .png files][:admin :"asset system" :font]
[1:12:32][Prevent LoadGlyphBitmap() and ExtractFont() from scaling][:font :rendering]
[1:13:11][Run our exporter–extractor successfully on both 512px and 800px high glyphs][:admin :"asset system" :font]
[1:14:00][Make ExtractFont() oversample by 2][:font :rendering]
[1:14:08][Run our exporter–extractor to find that we produced corrupted .png files][:admin :"asset system" :font]
[1:14:20][Step in to WritePNG() to see that the Width and Height are 0, and then on through LoadGlyphBitmap() to see what it does][:"asset system" :font :rendering :run]
[1:16:22][Change LoadGlyphBitmap() to increment the SampleInner][:"asset system" :font :rendering]
[1:16:54][Step back in to WritePNG() to still see a Width and Height of 0][:"asset system" :font :rendering :run]
[1:17:16][Fix LoadGlyphBitmap() to increment the Sample][:"asset system" :font :rendering]
[1:17:33][Step back in to WritePNG() to find more plausible Width and Height values][:"asset system" :font :rendering :run]
[1:17:37][View our glyphs to find that they appear squished horizontally, but antialiased][:admin :"asset system" :font :rendering]
[1:18:11][Fix LoadGlyphBitmap() to increment the Sample by the Scale][:"asset system" :font :rendering]
[1:18:23][Rerun our exporter–extractor and check the antialiasing of our correctly scaled glyphs][:admin :"asset system" :font :rendering]
[1:20:21][Increase the scaling to 4 in ExtractFont()][:font :rendering]
[1:20:39][Rerun our exporter–extractor and check the antialiasing of these ×4 oversampled glyphs][:admin :"asset system" :font :rendering]
[1:21:46][Prevent ExtractFont() from scaling][:font :rendering]
[1:22:00][Rerun our exporter–extractor and compare the antialiasing of our unscaled and oversampled glyphs][:admin :"asset system" :font :rendering]
[1:22:32][Increase the scaling to 8 in ExtractFont()][:font :rendering]
[1:22:45][Rerun our exporter–extractor and compare the antialiasing of our variously oversampled glyphs][:admin :"asset system" :font :rendering]
[1:23:59][Set our Scale amount to 4 in ExtractFont(), and briefly check the CreateFontA() documentation for the switch-over point of antialising[ref
        site="Windows Dev Center"
        page="CreateFontA function"
        url=https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-createfonta]][:font :rendering]
[1:26:08][Prevent ExtractFont() from scaling, to allow Windows to perform antialiasing][:font :rendering]
[1:26:29][Start to binary search the switch-over point of Windows' :font antialiasing][:admin :rendering]
[1:27:37][Make ExtractFont() pass the negative SamplePixelHeight to CreateFontA()][:font]
[1:27:50][Find that our glyphs are now larger, and explain the reason for this negative cHeight value[ref
        site="Windows Dev Center"
        page="CreateFontA function"
        url=https://docs.microsoft.com/en-us/windows/desktop/api/wingdi/nf-wingdi-createfonta]][:admin :font]
[1:28:54][Continue to binary search the switch-over point of Windows' :font antialiasing][:admin :rendering]
[1:32:13][Note that 354 is the magic value at which Windows stops antialiasing :font glyphs][:admin :rendering]
[1:35:48][Make ExtractFont() oversample if the pixel height is greater than 4][:font :rendering]
[1:36:42][Run our exporter–extractor on various glyph heights and check their antialiasing][:admin :"asset system" :font :rendering]
[1:37:39][Q&A][:speech]
[1:38:15][@vtlmks][Q: Perhaps your certificate for large font antialiasing died]
[1:38:35][@x13pixels][Q: In ExtractFont(), MaxGlyphDim's x value is set using TextMetric.tmOverhang. It seems like tmOverhang should only apply to MaxGlyphDim's y-value?][:font]
[1:39:27][@theomarest][Q: Would this only work for monospace fonts?][:font]
[1:39:34][@centhusiast][Q: What is the difference between the FreeType and TrueType fonts? Do both do the sub-pixel rasterization?][:font]
[1:40:08][@ivereadthesequel][@handmade_hero You wrote in the note 543->544 instead of 353->354. Glasses!][:font :rendering]
[1:40:19][Fix the antialiasing magic value note in ExtractFont()][:font]
[1:40:36][@boonetbe][Q: Did you try the Kakoune editor? Could its behavior be achieved in ~4coder?]
[1:41:48][@glog78][Q: Didn't MSN say something about small fonts too?][:font]
[1:42:51][@teamrandb][Q: But did you not check 500 and it worked?][:font]
[1:43:55][@floorislava][Q: GitHub bug report?]
[1:44:17][Close the "Support writing "large" PNGs" issue[ref
    site=GitHub
    page="HandmadeHero / cpp / Support writing \"large\" PNGs"
    url=https://github.com/HandmadeHero/cpp/issues/92]][:admin]
[1:44:42][Address the "Should we advance a character here?" issue[ref
    site=GitHub
    page="HandmadeHero / cpp / Should we advance a character here?"
    url=https://github.com/HandmadeHero/cpp/issues/93]][:parsing :research]
[1:46:22][Fix GetTokenRaw() to skip past the '.' of decimal numbers][:parsing]
[1:46:40][Close the "Should we advance a character here?" issue[ref
    site=GitHub
    page="HandmadeHero / cpp / Should we advance a character here?"
    url=https://github.com/HandmadeHero/cpp/issues/93]][:admin :parsing]
[1:47:36][@mycon_][Q: Are there any plans for a new HandmadeCon?[ref
        site="Handmade Hero"
        page="Handmade Hero-related Conferences"
        url=https://handmadehero.org/conference]]
[1:49:00][@centhusiast][Q: I followed your suggestions and used Roboto and Droid Sans fonts for my desktop app. They look good! Thanks for that. Do you have any other suggestions for a good looking :font?[ref
    site="Google Fonts"
    url=https://fonts.google.com/]]
[1:50:43][Close it down][:speech]
[/video]
