[video output=day469 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Downsampling Imported Assets" vod_platform=youtube id=OIIgYxV_1GI annotator=Miblo]
[0:01][Recap and set the stage for the day][:speech]
[2:02][:Research fast, good file hash: xxHash[ref
    site=xxHash
    url=https://cyan4973.github.io/xxHash/][ref
        site=GitHub
        page="RedSpah / xxhash_cpp"
        url=https://github.com/RedSpah/xxhash_cpp]][:hashing]
[5:21][Check out MurmurHash[ref
    site=Wikipedia
    page=MurmurHash
    url=https://en.wikipedia.org/wiki/MurmurHash][ref
        site=GitHub
        page="aappleby / smhasher / Wiki / MurmurHash3"
        url=https://github.com/aappleby/smhasher/wiki/MurmurHash3]][:hashing :research]
[13:06][Introduce MurmurHashUpdate() as a MurmurHash3[ref
        site=GitHub
        page="aappleby / smhasher / Wiki / MurmurHash3"
        url=https://github.com/aappleby/smhasher/wiki/MurmurHash3] and a 64-bit version of RotateLeft()][:"asset loading" :hashing]
[20:13][Introduce MurmurHashFinalize()[ref
        site=GitHub
        page="aappleby / smhasher / Wiki / MurmurHash3"
        url=https://github.com/aappleby/smhasher/wiki/MurmurHash3]][:"asset loading" :hashing]
[21:54][Consult the MurmurHash3 repo for the constant values suitable for 64-bit :hashing[ref
        site=GitHub
        page="aappleby / smhasher / Wiki / MurmurHash3"
        url=https://github.com/aappleby/smhasher/wiki/MurmurHash3]][:research]
[29:42][Enable MurmurHashUpdate() to perform the mixing step from the 128-bit MurmurHash3[ref
    site=GitHub
    page="aappleby / smhasher / src / MurmurHash3.cpp"
    url=https://github.com/aappleby/smhasher/blob/master/src/MurmurHash3.cpp]][:"asset loading" :hashing]
[31:04][Reflect on our chosen hash function and our unfortunate inability to gauge its strength][:hashing :speech]
[34:06][Implement CheckSumOf() as a MurmurHash3, permissively unaligned and for little-endian machines][:"asset loading" :hashing]
[41:56][][:hardware :speech][quote 622]
[42:01][Finish implementing CheckSumOf()][:"asset loading" :hashing]
[42:42][Decide against making ReadHHA_V0() produce the file's checksum][:"asset loading" :hashing :speech]
[44:16][Set up to test our importing][:"asset loading" :run]
[44:47][Create and inspect a new local.hha][:"asset loading" :run]
[45:47][Step in to AllocateGameAssets() and follow the asset importing process][:"asset loading" :run]
[48:11][Address the failed TagIndexInFile == TagCount assertion in WriteModificationsToHHA()][:"asset loading" :run]
[49:23][Create a new local.hha and step through WriteModificationsToHHA()][:"asset loading" :run]
[51:26][Fix WriteModificationsToHHA() to skip the null asset entry, and copy out the source tags][:"asset loading"]
[52:30][Continue to step through WriteModificationsToHHA() into the game][:"asset loading" :run]
[53:03][Check out our local.hha dump in TabView to see UNKNOWN types][:"asset loading" :run]
[55:26][Make ProcessTiledImport() set the Type][:"asset loading"]
[56:48][:Run the game, check out our local.hha dump and see that the bitmap types are now set][:"asset loading" :run]
[57:51][Step through AllocateGameAssets() to see if we correctly check for changes][:"asset loading" :run]
[59:26][Make AllocateGameAssets() set the asset BasicCategory][:"asset loading"]
[1:01:24][Recreate local.hha][:"asset loading" :run]
[1:02:05][][:speech][quote 623]
[1:02:11][Check the local.hha dump in TabView to see our BasicCategory settings][:"asset loading" :run]
[1:02:49][Determine to swizzle the R and G channels, and downsample our assets][:"asset loading" :rendering :speech]
[1:03:59][Downsampling of :Art Assets][:"asset loading" :blackboard :rendering]
[1:07:01][Streaming in assets from disk[ref
    site=StorageReview.com
    page="SSD vs HDD"
    url=https://www.storagereview.com/ssd_vs_hdd]][:"asset loading" :blackboard :hardware]
[1:10:03][Solving the streaming-from-disk problem by downsampling or compressing][:"asset loading" :blackboard :compression :rendering]
[1:13:39][Oversampling :art as a future-proofing measure][:blackboard]
[1:15:02][Set up to downsample our assets][:"asset loading" :rendering :speech]
[1:18:49][Enable ProcessTiledImport() to downsample our assets and swizzle their R and B channels][:"asset loading" :rendering]
[1:32:36][:Run the game without downsampling to see our asset][:"asset loading" :rendering]
[1:33:22][:Run the game downsampling by 2, to not see our asset][:"asset loading" :rendering]
[1:33:51][Check the local.hha dump in TabView to see nothing obvious wrong][:"asset loading" :run]
[1:34:50][Make ProcessTiledImport() stride through the pixels differently, and delinearize their colour][:"asset loading" :rendering]
[1:36:43][:Run the game to see parts of our asset][:"asset loading" :rendering]
[1:37:22][Fix ProcessTiledImport() to correctly stride through all the rows][:"asset loading" :rendering]
[1:38:30][:Run the game to see our asset, and consider that they do not have premultiplied alpha][:"asset loading" :rendering]
[1:39:25][Insert some investigative code in ProcessTiledImport() to determine whether or not the assets have premultiplied alpha][:"asset loading" :rendering]
[1:41:26][Break in to ProcessTiledImport() and watch the MaxBlueAlphaDiffC, to deduce that the alpha is not premultiplied][:"asset loading" :rendering :run]
[1:42:50][Make ProcessTiledImport() multiply each pixel's alpha into its colour][:"asset loading" :rendering]
[1:45:20][:Run the game and hit a long delay]
[1:46:28][Check out the nice clean edges on our asset][:"asset loading" :rendering :run]
[1:47:01][:Run the game a second time, and test it all in -O2][:"asset loading"]
[1:49:18][Q&A][:speech]
[1:49:51][@vateferfout][Q: At the end of the y loop of the downsample, shouldn't it be SourceBuffer0 = SourceBuffer1 + PrevDim; SourceBuffer1 = SourceBuffer0 + PrevDim; and x and y advancing by 2?][:rendering]
[1:51:01][@mmozeiko][Q: You added a comment for handling big-endianness for residual value when calculating hash, but I feel it is important to mention that the same comment should apply also for *At dereferencing in the loop. Loading u64 from byte array will also be affected by endianness and hash value will be different][:hardware :hashing]
[1:51:50][Make the big-endian comment apply to the whole of CheckSumOf()][:hardware :hashing]
[1:52:39][@zrizi][Q: (Off-topic) Are you the founder of Molly? How long ago did you start working there?]
[1:53:02][@jim0_o][Q: Does Anna draw Vector graphics initially and would you consider rasterising vector graphics in the asset system or at startup for a game like this?][:art :"asset loading"]
[1:54:23][@nxsy][Q: What sort of precision would we be losing by doing the downsamples from each other and doing srgb->linear->srgb, rather than, say, doing the linear conversion at the start and keeping it in linear, and doing the linear->srgb only when writing out each file?][:"asset loading" :rendering]
[1:56:28][@zrizi][Q: (Off-topic) Any suggestion / resource about how to implement a :networking layer from scratch for massive multiplayer games?]
[1:56:46][@nxsy][Q: I guess that’s a fun thing for me to test out][:rendering]
[1:59:06][@ivereadthesequel][Q: (Off-topic) Just curious, are there any games that require more accurate or complex digital filters on the image than those of bilinear or other approximations? Like any sort of sharp low pass filter, etc?][:rendering]
[2:00:49][@centhusiast][Q: Could you explain again the rotation to the left in the bit pattern you used?][:hashing]
[2:02:01][@zrizi][Q: I was thinking about a shooter. But let's think that we want to support multiplayer (over network) for [~hero Handmade Hero]][:networking]
[2:03:01][@graemephi][Q: (Off-topic, a bit) Can you give a quick description of the filter you designed? I'm fine with heavy DSP jargon][:rendering]
[2:03:41][@vaualbus][Q: There are no rotate left / right SSE / AVX intrinsics?[ref
    site=Intel
    page="Intel Intrinsics Guide"
    url=https://software.intel.com/sites/landingpage/IntrinsicsGuide/]][:isa]
[2:05:00][@frostyninja][Q: My girlfriend appreciates how much you hate on Microsoft and Windows (since I scream about it day in and out), but she said your keyboard sounds like someone's peeing in the next room and it has ruined my life]
[2:05:38][@zrizi][Q: But when client updates using server's incoming updates, assuming client simulates locally, it can create discontinuation if simulation diverged. Maybe in [~hero Handmade Hero] it cannot diverge that much, though][:networking]
[2:07:38][@vateferfout][You can just lerp between the client state and the server update][:networking]
[2:08:11][@jim0_o][Q: Would you need the brush strokes or would vector graphics from a conversion tool work? In Adobe Illustrator there is a quick and dirty conversion tool that I found works nicely for high-res cartoony graphics to vector graphics][:art]
[2:08:52][Shut it on down][:speech]
[/video]
