Compare commits

..

22 Commits

Author SHA1 Message Date
Miblo cf7db11289 Index hero/code667 2023-01-26 15:16:23 +00:00
Miblo 599fbf93c2 Index hero/code666 2022-12-22 21:47:41 +00:00
Miblo 85e55669fd Index hero/code665 2022-12-20 22:37:16 +00:00
Miblo 6d14b2b066 Index hero/code664 2022-12-07 21:46:30 +00:00
Miblo 5e47e9db58 Index hero/code663 2022-10-25 19:18:33 +01:00
Miblo 8d4004bf48 Index hero/code662
Also fix typos in code071 and code324
2022-09-22 20:02:06 +01:00
Miblo d5d46f014e Index hero/code661 2022-08-17 18:18:44 +01:00
Miblo 85d419d035 Index hero/code660 2022-08-16 17:55:32 +01:00
Miblo 82e8177be3 Index hero/code659
Also add new person Rocket and new medium Pet
2022-08-10 19:49:02 +01:00
Miblo 8a82432abb Index hero/chat020 2022-07-04 19:20:42 +01:00
Miblo 6ef907ff68 Index hero/code658 2022-06-23 22:04:33 +01:00
Miblo 2427b635df Index hero/code657 2022-06-22 22:20:16 +01:00
Miblo f970a792d1 Index hero/code656 2022-06-09 17:29:31 +01:00
Miblo 1bbff20746 Index hero/code655 2022-06-09 15:42:50 +01:00
Miblo 73279d012b Index hero/code654 2022-05-16 19:20:53 +01:00
Miblo 7e9caa9ea0 Index hero/code653 2022-05-13 20:58:18 +01:00
Miblo 67273a5018 Index hero/code652 2022-04-26 19:14:05 +01:00
Miblo e1a63e5e8f Index hero/code651 2022-04-22 18:01:45 +01:00
Miblo 2abb5ea731 Index hero/code650 2022-04-20 16:00:04 +01:00
Miblo c37bbb508b Index hero/code649
hero/code648: Fix typo
2022-04-13 19:36:19 +01:00
Miblo 1cf85b8e64 Index hero/code648 2022-04-04 23:01:37 +01:00
Matt Mascarenhas 4004b4abd4 Index hero/code647 2022-03-17 17:39:31 +00:00
26 changed files with 3176 additions and 2 deletions

View File

@ -13,3 +13,4 @@ medium = "research" { icon = "📖"; name = "Research"; }
medium = "run" { icon = "🏃"; name = "In-Game"; }
medium = "speech" { icon = "🗩"; name = "Speech"; }
medium = "trivia" { icon = "🎲"; name = "Trivia"; }
medium = "pet" { icon = "🐱"; name = "Pet Sounds"; }

View File

@ -21,6 +21,12 @@ person = "Molly"
name = "Molly";
}
person = "Rocket"
{
name = "Rocket";
}
person = "miblo"
{
name = "Matt Mascarenhas";

View File

@ -0,0 +1,238 @@
[video member=cmuratori stream_platform=twitch stream_username=handmade_hero project=chat medium=research title="Assembly Analysis and Front-end Register Clears" vod_platform=youtube id=R5tBY9Zyw6o annotator=Miblo]
[0:03][Welcome to the chat][:speech]
[1:32][Advocate ZII (Zero Is Initialisation)[ref
site=Imgur
page="Non zero'd and zero'd ASM"
url=https://imgur.com/a/xeX8GMk]][:language]
[8:38][Describe Jesse Meyer's ZII experiment[ref
site=Imgur
page="Non zero'd and zero'd ASM"
url=https://imgur.com/a/xeX8GMk]][:language]
[10:04][DOS vs Linux :memory mapping, page faults and :profiling]
[18:38][:Memory mapping and :profiling: 1) Hunt for minimum]
[22:04][:Memory mapping and :profiling: 2) Statistical breakdown, ignoring outliers]
[24:52][General advice on :profiling CPU :performance]
[25:42][Create xorclear.cpp][:programming :language :memory]
[27:24][Set up our xorclear experiment in Compiler Explorer[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:language :memory]
[28:55][Initially, msvc seems to generate better code than clang[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[32:17][Walk through the xorclear code in conjunction with the clang-generated assembly[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[39:14][Macro-ops subject to fusion (cmp and jne)[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[44:30][Memory Execution Units and Scalar Arithmetic Units][:hardware]
[46:36][Port usage of ADD (R64, I8)[ref
site="uops.info"
page="ADD (R64, I8)"
url=https://uops.info/html-instr/ADD_R64_I8.html]][:hardware :performance]
[49:50][Port usage of CMP (R64, I32)[ref
site="uops.info"
page="CMP (R64, I32)"
url=https://uops.info/html-instr/CMP_R64_I32.html]][:hardware :performance]
[51:27][Writing Identity into the Matrices array using mov, movaps and movups instructions[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[58:29][xorps[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language]
[1:00:28][Does Clang do anything more than -O3?][:language :speech]
[1:01:06][@chronic_quagga][-mavx2?][:language]
[1:01:21][Loading and writing zeros[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:04:40][Horrible code: 1) Superfluous zero writes[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:05:29][Try moving the Identity and Zero matrix_4x4 outside of main()[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:06:10][Move Identity and Zero matrix_4x4 back inside main()[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:06:22][Horrible code: 1) Superfluous zero writes (cont.)[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:06:52][Horrible code: 2) Using seven instructions to move 64 bytes[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:08:27][Hunt uops for mov[ref
site="uops.info"
url=https://uops.info/]][:hardware :performance]
[1:11:03][MOVUPS (M128, XMM)[ref
site="uops.info"
page="MOVUPS (M128, XMM)"
url=https://uops.info/html-instr/MOVUPS_M128_XMM.html]][:hardware :performance]
[1:14:56][Check the Intel 64 and IA-32 Architectures Software Developer Manual for MOV[ref
site="Intel"
page="Intel 64 and IA-32 Architectures Software Developer Manuals"
url=https://www-ssl.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html]][:hardware :performance]
[1:15:49][MOVQ (M64, XMM)[ref
site="uops.info"
page="MOVQ (M64, XMM)"
url=https://uops.info/html-instr/MOVQ_M64_XMM.html]][:hardware :performance]
[1:16:08][MOV permutations[ref
site="Intel"
page="Intel 64 and IA-32 Architectures Software Developer Manuals"
url=https://www-ssl.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html]][:hardware :performance]
[1:16:50][Port usage of mov, movaps and movups[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:hardware :performance]
[1:17:20][@jaege8][Next page?]
[1:17:59][MOV (M32, I32)[ref
site="uops.info"
page="MOV (M32, I32)"
url=https://uops.info/html-instr/MOV_M32_I32.html]][:hardware :performance]
[1:19:33][Horrible code: 2) Using seven instructions to move 64 bytes (cont.)[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:20:01][Hand-write and -read 128-bit rows using _mm_setr_ps() and _mm_storeu_ps()[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9][ref
site=Intel
page="Intel Intrinsics Guide"
url=https://software.intel.com/sites/landingpage/IntrinsicsGuide/]][:asm :language :memory]
[1:22:36][The clang-generated code is now better, with one loop unroll[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:25:42][@oldganon][O3 didn't help here][:language :performance]
[1:25:56][Thoughts on explicitly writing out intrinsics][:language :performance]
[1:26:54][Walk through the xorclear code in conjunction with the msvc-generated assembly[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:28:09][Hunt uops for rep[ref
site="uops.info"
url=https://uops.info/]][:hardware :performance]
[1:29:09][MOVSB_REPE[ref
site="uops.info"
page="MOVSB_REPE"
url=https://uops.info/html-instr/MOVSB_REPE.html]][:hardware :performance]
[1:30:59][Determine to try a dependent clear]
[1:32:15][@dragoonx6][@handmade_hero Try something like -O3 -march=skylake -ffast-math][:language]
[1:32:39][Temporarily try moving the Identity and Zero matrix_4x4 outside of main()[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:33:50][@daniel_collin_][You can leave it inside and set it to static][:language]
[1:35:16][Introduce a conditional clear in xorclear[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:39:14][Compare clang vs msvc on our conditional clear[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:44:14][@sainst0][Does it change if you give it -mtune=znver2?][:language]
[1:44:47][Clang often outputs slow code, but faster intrinsics-heavy code][:language :performance]
[1:45:34][Walk through the msvc-generated code for our conditional clear[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:46:22][Why clearing to zero is free[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :hardware :language :memory :performance]
[1:49:05][Non-free zero-clearing: 1) When frontend-bound][:hardware :performance]
[1:51:45][@peterfors][Skylake's memory subsystem is in charge of the loads and store requests and ordering. Since Haswell, it's possible to sustain two memory reads (on ports 2 and 3) and one memory write (on port 4) each cycle][:hardware :performance]
[1:52:29][Non-free zero-clearing: 2) Code size, alignment differences][:hardware :performance]
[1:53:22][Our movaps and xorps operations are free][:hardware :performance]
[1:53:58][Try declaring the rows uninitialised, only conditionally setting to zero[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:54:45][Our code introduced an extra jmp[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:56:20][Always initialise to zero[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[1:57:07][Replace the branch with a masked blend[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[2:02:22][msvc doesn't bother to blend with 0[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[2:04:41][Fill the second column with 1s[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[2:04:56][msvc doesn't bother to do the full blend on each row[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[2:05:30][Make each row different[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory]
[2:05:51][Our instructions will overlap[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:asm :language :memory :performance]
[2:07:09][Q&A][:speech]
[2:07:26][@jessem3y3r][@handmade_hero Hi [@cmuratori Casey]. Jesse from twitter here. Thank you so much for taking the time to explain and demonstrate this on [~hero Handmade Hero]! Deeply appreciated!]
[2:08:37][@somebody_took_my_name][If you take a look at different add / sub ops with immediates, you'll see nice tricks with the lea instruction][:asm]
[2:09:56][@centhusiast][Q: I compiled the code with icc, Intel's compiler, with O2 and it takes 3.5 seconds to run it. Is this really bad?][:performance]
[2:10:09][:Memory bandwidth will be the bottleneck][:performance :speech]
[2:13:35][@vodonikhs][Q: Someone has mentioned that older Clang versions generate better code. Could it be because of Heartbleed mitigation?][:language :performance]
[2:13:46][Try rolling back to older clang versions[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:language :performance]
[2:14:24][@i_am_seabass][Q: I read that mixing SSE2 and AVX2 will incur a :performance penalty. How would you handle optimizing code, if you want to support AVX2, but also SSE for older systems? Would you just have separate builds for each?]
[2:16:29][Isolating architecture-dependent code][:language :speech]
[2:18:34][@mindmark42][Q: Could you show what gcc does?][:language]
[2:18:43][GCC uses all scalar mov instructions[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:language :performance]
[2:19:18][@vodonikhs][Q: Try Clang 6][:language]
[2:19:24][Clang 6 still looks bad[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:language :performance]
[2:19:58][gcc -O3 generates the correct code[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:language :performance]
[2:20:26][@skincell3][Q: Could you provide the twitter conversation link that you are responding to, for the YouTube video?]
[2:21:03][@maliusarth][Q: You haven't tried latest clang with O3, did you?][:language]
[2:21:10][Latest clang with -O3 generates bad code[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:language :performance]
[2:21:13][Compilers should produce reliable code without the need for switches, optimisation passes, etc.][:language :performance]
[2:23:23][@sir_klausi][@handmade_hero Is it possible those extra jumps clang generates are a spectre mitigation?][:language]
[2:24:30][@drmaruq][Spectre mitigation is on :hardware level? Why would clang mess up the exe?][:language]
[2:25:05][Share the godbolt link[ref
site="Compiler Explorer"
page="xorclear"
url=https://godbolt.org/z/v36WE9]][:language :performance]
[2:25:33][Close it down with a plug of Star Code Galaxy[ref
site="Star Code Galaxy"
url=https://starcodegalaxy.com/]][:speech]
[/video]

View File

@ -11,7 +11,7 @@
[16:00][Point out the puzzler from world_position can be solved because we now no longer operate on entities without bringing them into the sim_region]
[17:28][Back to deal with compiler errors]
[23:37][The ground plane should not be the negative bottom sides of Tiles because we want to prevent things from accelerating near the Z bound]
[26:12][handmade_world.h: Tidy up the function ChunkPositionFromTilePostion]
[26:12][handmade_world.h: Tidy up the function ChunkPositionFromTilePosition]
[29:14][handmade_math.h: Use anonymous struct in union to grab part of the elements we are interested in v3]
[31:54][handmade_math.h: Make a v3 "constructor" that append a v2 with a real32 value]
[33:05][handmade_sim_region.h: Upgrade P/dP in sim_entity to v3]

View File

@ -36,7 +36,7 @@
[1:03:18][@snoringtortoise][In terms of asynchronous textures loading, the OpenGL website talks about pixel transfer operations and references glPixelStore. Did you look into these?[ref
site="Dominik Göddeke"
page="GPGPU::Fast Transfer Tutorial"
url="www.mathematik.tu-dortmund.de/~goeddeke/gpgpu/tutorial3.html"]]
url="https://www.mathematik.tu-dortmund.de/~goeddeke/gpgpu/tutorial3.html"]]
[1:06:22][@omnitechnomancer][Is that persistent texture mapping?[ref
site="OpenGL"
page="ARB_buffer_storage"

View File

@ -0,0 +1,156 @@
[video output=day647 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Debugging Simplified Lighting" vod_platform=youtube id=uWCt4b4ukAA annotator=Miblo]
[0:00][Recap and set the stage for the day][:speech]
[3:14][Demo the :lighting :performance][:run]
[4:19][Describe the old eight-ray octahedral :lighting][:research]
[7:06][Increase the SampleBatch loop from 16 to 64 in FullCast()][:lighting]
[7:22][Our :performance has degraded][:lighting :run]
[7:28][Decrease the SampleBatch loop from 64 to 8 in FullCast()][:lighting]
[7:36][We could easily hit 60 FPS][:lighting :performance :run]
[8:05][Consider moving the SampleBatch loop down to GridRayCast()][:lighting :research]
[10:27][Consider analysing the :sampling distribution of FullCast()][:lighting :research]
[12:17][Move the SampleBatch loop from FullCast() down to GridRayCast()][:lighting]
[14:17][Check the call stack of GridRayCast() for EntropyIndex][:lighting :research]
[15:16][Change FullCast() to take Entropy not as a pointer, and setup ComputeLightPropagationWork() increment the Entropy][:lighting :prng]
[16:20][Reacquaint ourselves with our random number generation][:prng :research]
[20:39][Make ComputeLightPropagationWork() get Entropy from RandomSeedOffset()][:lighting :prng]
[21:57][Consider usage of our random number code, and then just casting all 16 octahedrons][:lighting :prng :research]
[24:49][Remove entropy from FullCast() and make GridRayCast() just sample all the octahedrons][:lighting]
[31:41][Reacquaint ourselves with the sample direction picking code in GridRayCast()][:lighting :research]
[36:09][Fix GridRayCast() to correctly step through the :lighting table]
[37:56][Consider structuring the :lighting table with Rows being prime, and Octahedrons being interior][:research]
[39:12][Make GridRayCast() take an Sy value from FullCast(), for stepping through the sample table][:lighting]
[41:36][Remove Entropy from the call to FullCast() in ComputeLightPropagationWork()][:lighting]
[42:09][Our :lighting is now stable][:run]
[42:27][Increase tUpdateBlend from 1/60 to 15/60 in UpdateLighting()][:lighting]
[42:56][The :lighting doesn't seem to line up correctly when shifting around][:run]
[44:16][\~28ms per frame, and \~82% frame time on ComputeLightPropagationWork][:lighting :performance :run]
[45:45][Determine to debug the :lighting computation][:research]
[46:54][Walk through GridRayCast() and ComputeWalkTable() to refresh our memories][:lighting :research]
[52:52][Toggle on DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[53:01][Check out the light probes][:"debug visualisation" :lighting :run]
[54:11][Toggle on DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[54:21][Flood the debug system with vertices][:run]
[54:49][Make UpdateLighting() double the MaxDebugLineCount][:"debug visualisation" :lighting]
[54:56][Still flood the debug system with vertices][:run]
[55:03][Make PushLightingRenderValues() batch up the debug lines into 16-bit capable chunks][:"debug visualisation" :lighting]
[58:42][Still flood the debug system with vertices][:"debug visualisation" :lighting :run]
[58:58][Investigate the bug in our :lighting debug line batching][:"debug visualisation"]
[1:00:24][Decrease the batch size from U16Max to 4096 in PushLightingRenderValues()][:"debug visualisation" :lighting]
[1:00:45][Check out our spatial grid][:"debug visualisation" :lighting :run]
[1:03:05][Consider restoring our :lighting alignment][:run]
[1:04:57][Make UpdateLighting() offset the AtlasMinCorner by half a voxel][:lighting]
[1:07:34][Admire our light poisoning][:lighting :run]
[1:09:30][Comment out the AtlasMinCorner offset in UpdateLighting()][:lighting]
[1:09:43][Traverse the orphanage, pondering the offset-induced :lighting poisoning][:run]
[1:10:23][Consider why the :lighting alignment affects its feedback behaviour][:research]
[1:11:28][Let UpdateLighting() offset the AtlasMinCorner by half a voxel][:lighting]
[1:11:31][Take one last look at the light poisoning][:lighting :run]
[1:11:58][Toggle off DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[1:12:14][Consider it to be a sampling direction bug][:lighting :run]
[1:13:16][Toggle on DebugDrawOctahedralValues() in UpdateLighting(), and the octahedral map drawing][:"debug visualisation" :lighting]
[1:13:40][Check out our octahedral map koosh balls][:"debug visualisation" :lighting :run]
[1:15:06][Toggle on and make DebugDrawSpatialGrid() draw just the cell boundaries][:"debug visualisation" :lighting]
[1:15:35][Check out the cell boundaries in relation to the octahedral map koosh balls][:"debug visualisation" :lighting :run]
[1:16:10][Toggle on the occluder drawing in DebugDrawSpatialGrid()][:"debug visualisation" :lighting]
[1:16:22][Light probes inside light sources inconsistently see light and no light][:"debug visualisation" :lighting :run]
[1:18:27][@lfcdi][The hero's light box is sometimes red and sometimes green][:lighting]
[1:18:33][Demo the spatial grid checkerboard colouring][:"debug visualisation" :lighting :run]
[1:18:54][Toggle off the non-occluder drawing in DebugDrawSpatialGrid()][:"debug visualisation" :lighting]
[1:19:04][Demo the spatial grid checkerboard colouring][:"debug visualisation" :lighting :run]
[1:21:11][Determine to investigate the ray caster][:lighting :run]
[1:21:30][@horrowind][In handmade_lighting.cpp: line 152 SampleDir = ... Should the first factor be Sy*16*8?][:lighting]
[1:22:14][Explain the SampleDirectionTable indexing line in GridRayCast()][:lighting :research]
[1:24:13][@horrowind][I was just wondering because the outer index did not seem to incorporate two factors][:lighting]
[1:27:48][Set up to investigate the ray caster for bugs][:lighting :research]
[1:29:42][Scour FullCast() for bugs][:lighting :research]
[1:31:00][Make FullCast() write magenta into each SpecTexel inside geometry][:"debug visualisation" :lighting]
[1:33:35][Admire our magenta light probes][:"debug visualisation" :lighting :run]
[1:34:30][Lights incorrectly fail to pick up light][:"debug visualisation" :lighting :run]
[1:35:27][@ciansweeney][Debugging :lighting is the biggest pain in the ass]
[1:35:34][Optionally make FullCast() write black into each SpecTexel inside geometry][:"debug visualisation" :lighting]
[1:36:12][Our "inside" light probes are now black][:"debug visualisation" :lighting :run]
[1:36:28][Toggle off DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[1:37:01][Our light probes are picking up illogical light][:"debug visualisation" :lighting :run]
[1:38:26][Consult the SampleDirectionTable for clues regarding our illogical light probes][:lighting :research]
[1:40:23][@gregg_ink][So we got issues but that's not a problem for us because the worse they are, the faster we will fix them. Love that logic]
[1:43:45][Check the Remainder code in FullCast()][:lighting :research]
[1:47:00][The light probes inside geometry are correct, but our shifting block-copy is wrong][:lighting :run]
[1:48:11][Check that GridRayCast() and ComputeWalkTable() work in consort][:lighting :research]
[1:50:15][Consider replacing the walk table with on-the-fly computation][:lighting :research]
[1:52:21][Check that GridRayCast() and ComputeWalkTable() work in consort (cont.)][:lighting :research]
[1:57:14][Determine to draw a particular ray cast][:"debug visualisation" :lighting :run]
[1:58:37][Reduce the LightSamplingWalkTable pointer array from 8 to 4 in lighting_solution][:"data structure" :lighting]
[1:59:15][The :lighting looks the same][:run]
[1:59:32][Scour GridRayCast() for bugs][:lighting :research]
[2:03:00][Increase MaxCostPerRay from 8 to 16 in UpdateLighting()][:lighting]
[2:03:52][\~38ms per frame, and \~69% frame time on ComputeLightPropagationWork][:lighting :performance :run]
[2:04:21][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[2:04:27][\~27ms per frame, and \~81% frame time on ComputeLightPropagationWork][:lighting :performance :run]
[2:04:51][Toggle on DebugDrawOctahedralValues() and decrease MaxCostPerRay back from 16 to 8 in UpdateLighting()][:lighting]
[2:06:41][Re-enable ray drawing in GridRayCast()][:"debug visualisation" :lighting]
[2:09:04][Reacquaint ourselves with RectCenterDim() and the ProbeSamplePSingle value in GridRayCast()][:lighting :research]
[2:12:17][Enable GridRayCast() to use ProbeSamplePSingle and ProbeSampleNSingle for drawing][:"debug visualisation" :lighting]
[2:14:05][Consider supporting picking of a particular ray][:lighting :research]
[2:15:51][Re-enable ray cast drawing in FullCast()][:"debug visualisation" :lighting]
[2:19:12][Hunt in vain for our drawn ray cast][:"debug visualisation" :lighting :run]
[2:19:36][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[2:19:57][Hunt in vain for our drawn ray cast][:"debug visualisation" :lighting :run]
[2:20:12][Decrease DebugGridIndex from 717 to 200 and DebugRayIndex from 531 to 0 in UpdateLighting()][:"debug visualisation" :lighting]
[2:21:27][Hunt in vain for our drawn ray cast][:"debug visualisation" :lighting :run]
[2:21:42][Elevate GRID_RAY_CAST_DEBUGGING to the top of handmade_lighting.h][:lighting]
[2:22:46][Break in to FullCast() to find that we never get to our DebugGridIndex of 200][:lighting :run]
[2:24:41][The spatial partition is half the voxel dimensions, a mere 96][:lighting :research]
[2:25:43][Decrease DebugGridIndex from 200 to 30 in UpdateLighting()][:"debug visualisation" :lighting]
[2:26:04][Break in to FullCast() and see our drawn ray cast][:"debug visualisation" :lighting :run]
[2:28:03][Re-enable support for debug ray picking in FullCast(), introducing debug_ray_pick][:"data structure" :lighting]
[2:34:05][Quick break for water and snacks][:admin]
[2:34:34][@insobot][Allocates 256 megs, keeps playing. Employees are encouraged to kill yourself]
[2:34:52][@bluemelon555][Are you providing the snacks?]
[2:35:03][:afk]
[2:47:31][Return with water and snacks][:admin]
[2:48:41][@choosetheforce][I used to inhale that stuff as a kid]
[2:48:51][Resume re-enabling support for debug ray picking in FullCast()][:lighting]
[2:53:28][The magenta "expected direction" line does not go in the direction we ray cast][:"debug visualisation" :lighting :run]
[2:55:12][Investigate the "expected" and "ray" direction misalignment in FullCast()][:lighting :research]
[2:56:27][Try making FullCast() add 1 to the ExpectedDirection axes to account for the apron][:lighting]
[2:56:47][The "expected" and "ray" directions remain misaligned][:"debug visualisation" :lighting :run]
[2:56:59][Investigate the "expected" and "ray" direction misalignment in FullCast() and GridRayCast()][:lighting :research]
[2:58:29][The "expected" and "ray" lines only need to come out of the same face of the octahedron][:"debug visualisation" :lighting :run]
[2:58:56][Re-enable editing of the ray picking values in DEBUGInteract() and DEBUGBeginInteract()][:lighting :ui]
[3:03:05][Try editing GridIndex in-game][:"debug visualisation" :lighting :run :ui]
[3:04:06][Clamp the DebugTick values in FullCast()][:lighting]
[3:06:53][GridIndex 48 yields two sets of ray casting][:"debug visualisation" :lighting :run :ui]
[3:07:48][Replace GridIndex with a v3s AtlasIndex in debug_ray_pick, for more specific ray picking][:"data structure" :lighting]
[3:11:09][Introduce a v3s version of Clamp()][:mathematics]
[3:12:11][Make FullCast() keep the AtlasIndex in range][:lighting]
[3:12:25][Try unsuccessfully to edit AtlasIndex][:"debug visualisation" :lighting :run :ui]
[3:13:10][Add s32 editing support to DEBUGInteract() and DEBUGBeginInteract()][:lighting :ui]
[3:13:48][Try editing our AtlasIndex values][:"debug visualisation" :lighting :run :ui]
[3:14:52][Add DevUI_Interaction_TickValue to edit integer values by clicking (rather than dragging)][:lighting :ui]
[3:17:48][Decrementing by clicking works, but incrementing does not][:"debug visualisation" :lighting :run :ui]
[3:18:07][Fix DEBUGInteract() to increment integer values by clicking][:lighting :ui]
[3:18:21][Click-and-hold increments integer values][:"debug visualisation" :lighting :run :ui]
[3:18:34][Make DEBUGEndInteract() rather than DEBUGInteract() handle integer editing by clicking][:lighting :ui]
[3:19:21][Our integer editing is more sane, but still doesn't clamp][:"debug visualisation" :lighting :run :ui]
[3:20:47][Atlas (10, 4, 1) on our octahedral map has a straight-down expected direction][:"debug visualisation" :lighting :run :ui]
[3:21:39][Investigate our straight-down expected direction][:lighting :research]
[3:23:50][@gregg_ink][Are light bleed and light poisoning the same thing?][:lighting]
[3:26:34][Inspect atlas (10, 4, 1)][:"debug visualisation" :lighting :run]
[3:27:04][Initialise AtlasIndex to 10, 4, 1 UpdateLighting()][:lighting]
[3:27:14][Ray casting on AtlasIndex (10, 4, 1) fails from Octahedron 4 onwards][:"debug visualisation" :lighting :run]
[3:27:42][Investigate SampleDirectionTable and GridRayCast() for the source of our ray casting failure][:lighting :research]
[3:31:20][Octahedron 4 to 15 remain incorrect][:"debug visualisation" :lighting :run]
[3:32:22][Check again that GridRayCast() and ComputeWalkTable() work in consort][:lighting :research]
[3:35:05][Initialise DirOffset in GridRayCast() for easy inspection][:lighting]
[3:35:52][Step in to GridRayCast() and inspect DirOffset and RayDSingle, to find values we didn't think existed in handmade_sampling_spheres.inl][:lighting :run]
[3:40:23][@ono_sendai_][Is this 2D or 3D global illumination?][:lighting]
[3:41:55][Determine to fix GenerateOctahedralLightingPattern() next time][:lighting :research]
[3:46:16][@poissonprocess][Poisson distributions!][:sampling]
[3:46:25][Consider keeping Poisson distribution :sampling][:lighting :research]
[3:48:20][@spacenaming][Will it still be mapped to the octahedral map? Because if so, couldn't we just generate the noise on there? That is a square surface, right?][:lighting]
[3:49:44][Determine to rebuild SampleDirectionTable next time][:lighting :research]
[3:50:19][Set up GridRayCast() to traverse the SampleDirectionTable in a single loop][:lighting]
[3:52:37][Call it here, with the determination to rebuild SampleDirectionTable next time][:speech]
[3:53:21][Consider the possibility of smarter ways to batch up ray processing][:lighting :research]
[3:54:32][Thank you, everyone][:speech]
[/video]

View File

@ -0,0 +1,134 @@
[video output=day648 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Rebuilding Light Tables" vod_platform=youtube id=hNAuQyyuUtE annotator=Miblo]
[0:01][Recap and set the stage for the day building light tables][:lighting :speech]
[1:16][Demo our :lighting colour bleed][:run]
[2:07][Our SampleDirectionTable in handmade_sampling_spheres.inl samples direction \[0, 0, 1\] multiple times][:lighting :research]
[3:35][Plan to rebuild our light table in an evenly distributed blue noise pattern][:lighting :research :sampling]
[5:59][Consider :sampling the light at 16 samples per texel][:lighting :research]
[7:25][@bashtardis][You also need it to be blue-noise temporally as well as spatially for best result][:lighting :sampling]
[7:53][Consider using a pseudo-blue noise :sampling pattern, or tuning the distance parameter manually][:lighting :research]
[9:13][Toggle on the sphere drawing in PushLightingRenderValues()][:"debug visualisation" :lighting]
[9:46][Check out our :sampling sphere][:lighting :run]
[10:22][Plan to rebuild the table then view our drawing][:lighting :research :sampling]
[10:46][Reacquaint ourselves with hhsphere.cpp][:lighting :research :sampling]
[14:08][Remove SamplingSpheres from lighting_solution, the LightSamplingSphereFloatTable from handmade_sampling_spheres.inl with its generator in OutputSphereINL(), InterleaveDirections(), cube_store and sphere_store][:"data structure" :lighting :metaprogramming :sampling]
[18:17][Plan to make OutputSphereINL() output the SampleDirectionTable with all the octahedral rays for a given texel, then all those for the next texel, etc.][:lighting :metaprogramming :research :sampling]
[20:20][Make OutputSphereINL() output the SampleDirectionTable with all the octahedral rays for a given texel, then all those for the next texel, etc.][:lighting :metaprogramming :sampling]
[24:40][Reacquaint ourselves with the light sample sieving in GeneratePoissonDistribution()][:lighting :metaprogramming :research :sampling]
[26:41][Propose to draw the sampling sphere coloured by texel, then fix hhsphere.cpp][:"debug visualisation" :lighting :research :sampling]
[27:32][Make PushLightingRenderValues() draw the sampling sphere coloured by texel][:"debug visualisation" :lighting :sampling]
[33:18][Rework GenerateOctahedralLightingPattern() to structure the sampling directions with all the octahedral rays for a given texel, then all those for the next texel, etc.][:lighting :metaprogramming :sampling]
[35:58][The bug: Our call to GeneratePoissonDistribution(), with its randomness, using TotalDirectionCount, may yield fewer samples on a texel than we need][:lighting :research :sampling]
[37:38][Consider asking GeneratePoissonDistribution() for more sampling points][:lighting :research :sampling]
[38:40][Introduce direction_gen for GeneratePoissonDistribution() to return, and remove GeneratePoissonSamples(), TestFunc() and GeneratePoissonLightingPattern()][:"data structure" :lighting :metaprogramming :sampling]
[42:48][Hunt for a v2u + operator overload][:language :research]
[44:08][Introduce a v2u + operator overload][:language]
[44:37][Update GenerateOctahedralLightingPattern() to use our direction_gen, and ask GeneratePoissonDistribution() for 20% more samples than we'll use, introducing AllocDirArray()][:lighting :metaprogramming :sampling]
[51:34][Make GenerateOctahedralLightingPattern() print an error on "Direction count underflow for texel"][:lighting :metaprogramming :sampling]
[52:47][Finish up the usage code of hhsphere.cpp][:lighting :metaprogramming :sampling]
[57:38][Run hhsphere, and hit a number of "Direction count underflow for texel" errors][:admin :lighting :sampling]
[59:21][Inspect handmade_sampling_spheres.inl, try to compile with it and hit a syntax error][:language :lighting :research :sampling]
[1:00:25][Manually append a ")" to TOTAL_LIGHT_SAMPLE_DIRECTION_COUNT in handmade_sampling_spheres.inl][:language]
[1:01:29][Remove stale #if 0 from GridRayCast()][:language]
[1:01:42][Append the missing ")" to TOTAL_LIGHT_SAMPLE_DIRECTION_COUNT OutputSphereINL()][:lighting :metaprogramming :sampling]
[1:01:52][Update GridRayCast() to use our newly structured SampleDirectionTable][:lighting :sampling]
[1:18:09][Hit a read access violation in GridRayCast()][:lighting :run :sampling]
[1:18:43][Investigate our read access violation in GridRayCast()][:lighting :run :sampling]
[1:21:02][Reacquaint ourselves with tTerminate in ComputeWalkTable()][:lighting :research :sampling]
[1:25:24][Make ComputeWalkTable() set tTerminate to 0 if greater than or equal to 1000000]
[1:27:20][Plan to update ~remedybg from 0.3.5.0 to 0.3.6.3][:admin]
[1:28:05][Again hit a read access violation in GridRayCast()][:lighting :run :sampling]
[1:29:39][Let ComputeWalkTable() use tTerminate as is, and instead make GenerateOctahedralLightingPattern() output a valid \[0, 0, 1\] ray direction on underflow][:lighting :metaprogramming :sampling]
[1:30:58][Run hhsphere, and hit a number of "Direction count underflow for texel" errors][:admin :lighting :sampling]
[1:31:49][Inspect handmade_sampling_spheres.inl and compile just fine][:lighting :research :sampling]
[1:32:29][:Run the game without crashing, but with the sampling sphere possibly being drawn wrong][:lighting :sampling]
[1:33:12][Check RenderDiagrams() for participation in :lighting][:"debug visualisation" :research]
[1:34:12][Make PushLightingRenderValues() draw the sampling sphere lower down][:"debug visualisation" :lighting :sampling]
[1:34:31][Our sampling sphere is lit, and contains gaps][:lighting :run :sampling]
[1:35:55][Fix GridRayCast() to set TransferPPS\[Tx\] to the already accumulated TransferPPSAccum][:lighting :sampling]
[1:37:11][Our lighting is no longer overblown, but still bleeds, and dims while moving][:lighting :run :sampling]
[1:39:19][Try making GenerateOctahedralLightingPattern() ask GeneratePoissonDistribution() for 100% more samples than we'll use, and tighten the convergence criteria from 0.025 to 0.0125][:lighting :metaprogramming :sampling]
[1:41:39][Run hhsphere without completing][:admin :lighting :sampling]
[1:42:41][Revert the convergence criteria to 0.025 in GenerateOctahedralLightingPattern()][:lighting :metaprogramming :sampling]
[1:43:13][Run hhsphere, and still hit a number of "Direction count underflow for texel" errors][:admin :lighting :sampling]
[1:43:46][Investigate why GenerateOctahedralLightingPattern() is not receiving enough sample directions][:lighting :research :sampling]
[1:47:03][Our lighting sphere looks the same][:"debug visualisation" :lighting :run :sampling]
[1:47:17][We're missing something][:lighting :research :sampling]
[1:48:11][Break for snacks][:admin]
[1:48:38][:afk]
[1:51:56][Return with snacks][:admin]
[1:52:12][Consider abandoning vs debugging the sampling point picking scheme][:lighting :research :sampling]
[1:56:40][@tomisqi][What snacks?]
[1:57:21][Need more chicharrones][:food :speech]
[1:57:48][Consider evenly distributing sampling points in texel space][:lighting :research :sampling]
[1:59:01][Propose seeding 16 rays per texel, using a white noise distribution, repulsed to increase evenness, and prevented from leaving their containing texel][:lighting :research :sampling]
[2:01:02][@spacenaming][Won't you get clamping on the edges?][:lighting :sampling]
[2:01:37][Consider starting with the 16 rays per texel white noise distribution, without repulsion][:lighting :research :sampling]
[2:02:09][Make GeneratePoissonDistribution() seed the requested rays per texel in a white noise distribution, and remove GenerateOctahedralLightingPattern()][:lighting :metaprogramming :sampling]
[2:09:23][Run hhsphere, and find a more coherent SampleDirectionTable][:admin :lighting :sampling]
[2:09:55][Our lighting sphere is only half filled in][:"debug visualisation" :lighting :run :sampling]
[2:10:32][Fix GeneratePoissonDistribution() to produce a -1 to 1 distribution][:lighting :metaprogramming :sampling]
[2:11:58][Run hhsphere][:admin :lighting :sampling]
[2:12:09][Our lighting sphere is complete, if clumpy][:"debug visualisation" :lighting :run :sampling]
[2:13:05][Make GeneratePoissonDistribution() repulse the rays, keeping them in the same quadrant][:lighting :metaprogramming :sampling]
[2:18:16][Run hhsphere and quickly lock up][:admin :lighting :sampling]
[2:19:08][Loosen the convergence criteria from 0.025 to 0.14 in GeneratePoissonDistribution()][:lighting :metaprogramming :sampling]
[2:19:35][Run hhsphere to completion][:admin :lighting :sampling]
[2:19:52][Our lighting sphere is not horrible, but good enough for now][:"debug visualisation" :lighting :run :sampling]
[2:21:19][Our rays now look more sane][:"debug visualisation" :lighting :run]
[2:22:26][Make FullCast() clamp the RayIndex to the total count minus 1][:lighting]
[2:22:34][Determine to investigate our green light leakage][:"debug visualisation" :lighting :run]
[2:23:19][Investigate our green light leakage][:lighting :research]
[2:24:47][Toggle on the light atlas drawing in OpenGLEndFrame()][:"debug visualisation" :lighting]
[2:24:56][Our light atlases clearly contain energy bleed][:"debug visualisation" :lighting :run]
[2:25:08][Make OpenGLChangeToSettings() draw our light atlases in their entirety][:"debug visualisation" :lighting]
[2:26:35][Check out our full light atlases][:"debug visualisation" :lighting :run]
[2:26:49][Make OpenGLChangeToSettings() draw 0.25 of our light atlases in both X and Y][:"debug visualisation" :lighting]
[2:27:02][Glimpse our light atlases][:"debug visualisation" :lighting :run]
[2:27:11][Make OpenGLChangeToSettings() draw 0.025 of our light atlases in both X and Y][:"debug visualisation" :lighting]
[2:27:34][Glimpse our light atlases][:"debug visualisation" :lighting :run]
[2:27:37][Make OpenGLChangeToSettings() draw 0.025 of our light atlases in X][:"debug visualisation" :lighting]
[2:28:05][Check out our light atlases][:"debug visualisation" :lighting :run]
[2:28:35][Make OpenGLChangeToSettings() draw 0.0125 of our light atlases in X][:"debug visualisation" :lighting]
[2:28:46][Our light atlases have a consistent light bleed][:"debug visualisation" :lighting :run]
[2:28:55][Let OpenGLChangeToSettings() draw the original portion of our light atlases][:"debug visualisation" :lighting]
[2:29:04][Traverse the orphanage and watch the light bleed in certain areas][:"debug visualisation" :lighting :run]
[2:30:54][Start by investigating BlockCopyAtlas()][:lighting :research]
[2:32:05][Assert in UpdateLighting() that dVoxel.z is 0][:lighting]
[2:32:23][Correctly fail to hit the dVoxel.z assertion][:lighting :run]
[2:32:36][Scour UpdateLighting() for errors in other dVoxel values][:lighting :research]
[2:35:21][Assert in UpdateLighting() that dVoxel.x and dVoxel.y are <= 1][:lighting]
[2:36:18][Hit our dVoxel.x assertion][:lighting :run]
[2:36:30][Make UpdateLighting() skip the dVoxel.x and dVoxel.y assertions first time round][:lighting]
[2:37:05][Correctly fail to hit the dVoxel.x and dVoxel.y assertions][:lighting :run]
[2:37:15][Remove the dVoxel.x and dVoxel.y assertions from UpdateLighting()][:lighting :run]
[2:37:36][Scour BlockCopyAtlas() for bugs][:lighting :research]
[2:39:52][Traverse the orphanage and watch the light bleed in certain areas][:"debug visualisation" :lighting :run]
[2:40:03][Toggle off the light atlas drawing in OpenGLEndFrame()][:"debug visualisation" :lighting]
[2:40:15][Traverse the orphanage and carefully watch the lighting at a slow 0.04 timestep][:"debug visualisation" :lighting :run]
[2:41:50][Set tUpdateBlend to 1 in UpdateLighting()][:lighting]
[2:42:07][The lighting clearly blinks when copying the atlases][:"debug visualisation" :lighting :run]
[2:43:29][Scour BlockCopyAtlas() for bugs][:lighting :research]
[2:44:32][Toggle on the LIGHT_ATLAS_ASSERT for VALIDATE_TEXEL_ATLAS() to fire][:lighting]
[2:44:43][Trap on VALIDATE_TEXEL_ATLAS() of the DiffuseAtlas][:lighting :run]
[2:45:11][Make ValidateTexelComponent() consider a component of between -100 and 100 to be valid][:lighting]
[2:45:30][Immediately trap on VALIDATE_TEXEL_ATLAS() of the SpecAtlas][:lighting :run]
[2:45:44][Consider deferring until next time the investigation of our out-of-bounds lighting values][:lighting :research]
[2:49:13][Introduce VoxelIndexIsInDim() for GridRayCast() to assert that the sample fetch is in bounds][:lighting]
[2:55:54][Hit our IsInBounds assertion in GridRayCast()][:lighting :run]
[2:58:36][Get it][:lighting :research]
[3:00:34][Toggle off the ray drawing in PushLightingRenderValues(), and toggle on DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[3:01:36][Immediately trap on VALIDATE_TEXEL_ATLAS() of the SpecAtlas][:lighting :run]
[3:01:49][Toggle off the LIGHT_ATLAS_ASSERT][:lighting]
[3:01:57][Our bug: We can sample garbage in Z when not hitting an occluder][:"debug visualisation" :lighting :run]
[3:06:26][GridRayCast() is already clamping][:lighting :research]
[3:09:10][Scour GridRayCast() for a subtle bug causing out-of-bounds sampling][:lighting :research]
[3:14:00][Set the first entry of SampleDirectionTable to an invalid \[0, 0, 0\]][:lighting]
[3:14:49][Hit our read access violation in GridRayCast() on an invalid \[0, 0, 0\] sample direction][:lighting :run :sampling]
[3:14:52][Inspect the values in GridRayCast() on an invalid \[0, 0, 0\] sample direction][:lighting :run :sampling]
[3:18:21][GridRayCast() produces a bogus Txy value][:lighting :run :sampling]
[3:19:17][Revert the first entry of SampleDirectionTable to the generated value][:lighting]
[3:19:25][Consider calling it for today][:speech]
[3:20:04][Take one last look at our light bleed, blinking on copy and light source occlusion][:lighting :run]
[3:23:06][@midnightsun55][Brooo what is going on, [@cmuratori Casey] is about to do Unreal Engine 6 by himself at this point]
[3:23:18][Call it for today][:speech]
[/video]

View File

@ -0,0 +1,116 @@
[video output=day649 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Removing Lighting Walk Tables" vod_platform=youtube id=kcmku4TMTek annotator=Miblo]
[0:02][Recap and set the stage for the day debugging :lighting][:speech]
[1:03][Demo our light bleed bug][:lighting :run]
[1:45][Demo our light copying bug][:lighting :run]
[6:00][Describe BlockCopyAtlas()][:lighting :research]
[7:09][Assert in BlockCopyAtlas() that the Z loop doesn't happen][:lighting]
[7:50][Hit our Z loop assertion in BlockCopyAtlas()][:lighting :run]
[8:49][Move our Z loop assertion in BlockCopyAtlas() down to the Z clearing loop][:lighting]
[9:11][Hit our Z clearing loop assertion in BlockCopyAtlas()][:lighting :run]
[9:45][Inspect the BlockCopyAtlas() values in an -Od build][:lighting :run]
[11:26][Comment out the Z clearing loop in BlockCopyAtlas()][:lighting]
[11:51][Try to eyeball our light copying bug][:lighting :run]
[12:14][Toggle off DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[12:44][Our light copying / flashing bug seems to still occur][:lighting :run]
[14:47][Uncomment the Z clearing loop in BlockCopyAtlas()][:lighting]
[15:14][Scour BlockCopyAtlas() for bugs][:lighting :research]
[18:07][Remove the minus 1 from the StopZ computation in BlockCopyAtlas()][:lighting]
[18:35][We still see a little bit of flashing][:lighting :run]
[18:54][Enable LIGHT_ATLAS_ASSERT][:lighting]
[19:25][Immediately trap on VALIDATE_TEXEL_ATLAS() of the SpecAtlas][:lighting :run]
[19:35][Toggle off the VALIDATE_TEXEL_ATLAS() calls in UpdateLighting()][:lighting]
[19:47][Trap on VALIDATE_TEXEL_ATLAS() in BlockCopyAtlas()][:lighting :run]
[19:54][Toggle off the VALIDATE_TEXEL_ATLAS() calls using #if TEMPORARY][:lighting]
[20:19][Trap on VALIDATE_TEXEL_ATLAS() at the end of BlockCopyAtlas()][:lighting :run]
[20:29][Toggle off the final VALIDATE_TEXEL_ATLAS() call using #if TEMPORARY][:lighting]
[20:43][Successfully :run without fetching out of bounds][:lighting :run]
[21:02][Remove the minus 1 from the StopX and StopY computations in BlockCopyAtlas()][:lighting]
[21:22][We have :lighting movement across tiles][:run]
[23:25][Decrease tUpdateBlend from 1 to 15/60 in UpdateLighting()][:lighting]
[23:49][Still see the :lighting shift][:run]
[24:13][Decrease tUpdateBlend from 15/60 to 1/60 in UpdateLighting()][:lighting]
[24:29][The shift is due to the light being recomputed differently][:lighting :run]
[25:22][Toggle off the -1 to 1 origin cube in UpdateAndRenderWorld()][:"debug visualisation" :lighting]
[26:59][The wall tiles darken after shifting][:lighting :run]
[28:07][Toggle off PushLight() on the DebugLightP in UpdateAndRenderWorld()][:lighting]
[28:26][The room still seems to brighten when we enter][:lighting :run]
[30:18][The light bleed takes longer with our slower tUpdateBlend][:lighting :run]
[31:01][Increase tUpdateBlend from 1/60 to 1 in UpdateLighting()][:lighting]
[31:50][The copy is now fine, but the ray casting differs when shifting the lighting voxel][:lighting :run]
[34:12][Prevent UpdateLighting() from offsetting VoxCameraOffset.Y by 2][:lighting]
[35:03][The lighting region is now centred][:lighting :run]
[36:38][Scour GridRayCast() for a reason for differences when shifting the lighting voxel][:lighting :research]
[41:16][Scour ComputeWalkTable() for bugs][:lighting :research]
[42:40][Make WalkTableOffset be an array of 4 in sample_direction, for ComputeWalkTable() to use][:"data structure" :lighting]
[43:12][The light doesn't seem to have changed][:lighting :run]
[43:58][Double-check ComputeWalkTable() for correctness][:lighting :research]
[45:16][Consider removing lighting walk tables][:lighting :research]
[46:56][The ray casting still differs when shifting the lighting voxel][:lighting :run]
[47:27][Consider making UpdateLighting() force dVoxel to be a multiple of 2 so the quadrant doesn't change][:lighting :research]
[48:32][@gir33][The problem changed, though, there's still a dark spot but it doesn't move now][:lighting]
[48:51][Demo the moving dark spot][:lighting :run]
[49:46][@gir33][I mean it seems like it only moved when leaving the room but not while moving within the room as before, no?][:lighting]
[50:07][Demo the changing dark spot when the lighting voxel alignment changes within a room][:lighting :run]
[50:59][Consider removing lighting walk tables][:lighting :research]
[55:15][@mallesbixie][FruFru is a great variable name, though]
[55:20][Consider removing lighting walk tables][:lighting :research]
[56:18][Check GridRayCast() to inform our lighting walk table removal decision][:lighting :research]
[59:50][Toggle on WalkTable stepping in GridRayCast()][:lighting]
[1:00:06][Traverse the orphanage into a relatively stably lit room][:lighting :run]
[1:00:17][Change the CostMetric-based ray casting loop in GridRayCast() to iterate over a hard-bounded GridWalkIteration][:lighting]
[1:00:47][The lighting looks the same][:lighting :run]
[1:00:56][Remove CostMetric entirely from GridRayCast()][:lighting]
[1:01:23][The lighting remains fine][:lighting :run]
[1:01:46][Consider formulating an exit criterion in GridRayCast() upon leaving the spatial partition][:lighting :research]
[1:04:29][Determine to make GridRayCast() work without a walk table][:lighting :research]
[1:09:25][Sketch out walk table-eliminated grid stepping in GridRayCast()][:lighting]
[1:45:42][@spacenaming][DirCurP is 2*DirCurP+dX/Y at the moment][:lighting]
[1:46:06][@spacenaming][XStepV have it included already][:lighting]
[1:46:35][Determine to remove lighting walk tables][:lighting :research]
[1:47:31][Break][:admin]
[1:48:10][:afk]
[1:50:06][Return and centre the camera][:admin]
[1:52:25][Implement on-the-fly grid stepping in GridRayCast()][:lighting]
[2:13:50][Hit an overflow read access violation on SpatialGridLeaves in GridRayCast()][:lighting :run]
[2:14:03][Introduce a CheckGridIndex to separate out the two grid stepping routines in GridRayCast()][:lighting]
[2:14:46][The lighting behaves the same as before][:lighting :run]
[2:15:11][Break in to GridRayCast() and compare the values of the two grid stepping routines][:lighting :run]
[2:16:33][Fix the dGridIndexXBase and dGridIndexYBase computations in GridRayCast()][:lighting]
[2:16:51][Break in to GridRayCast() and compare the values of the two grid stepping routines][:lighting :run]
[2:17:51][Assert in GridRayCast() that GridIndex and CheckGridIndex match][:lighting]
[2:18:14][:Run the game][:lighting]
[2:18:24][Update ~remedybg from 0.3.5.0 to 0.3.6.4][:admin]
[2:20:21][Hit the GridIndex and CheckGridIndex matching assertion in GridRayCast()][:lighting :run]
[2:21:49][Swap in the new on-the-fly grid stepping in GridRayCast()][:lighting]
[2:22:49][Our ray casting correctly no longer differs when shifting the lighting voxel][:lighting :run]
[2:24:19][Consider how to update tTerminate][:lighting :research]
[2:29:46][Make GridRayCast() compute tTerminate on the fly][:lighting]
[2:38:43][Our lighting happily looks no different][:lighting :run]
[2:39:08][Remove the :lighting walk tables][:lighting]
[2:41:08][:Run successfully and briefly consider our remaining light bleed bug][:lighting]
[2:44:28][Reflect on today's work and consider further simplifications][:lighting :speech]
[2:45:35][\~82% frame time (\~400,000,000 cycles) on ComputeLightPropagationWork][:lighting :performance :run]
[2:46:43][Make GridRayCast() only cast one ray][:lighting]
[2:47:05][\~35% frame time (\~35,000,000 cycles) on ComputeLightPropagationWork][:lighting :performance :run]
[2:47:36][Make GridRayCast() cast the full LIGHTING_OCTAHEDRAL_RAYS_PER_TEXEL][:lighting]
[2:47:42][\~82% frame time (\~400,000,000 cycles) on ComputeLightPropagationWork][:lighting :performance :run]
[2:48:00][Make GridRayCast() only cast no rays][:lighting]
[2:48:08][\~11% frame time (\~8,800,000 cycles) on ComputeLightPropagationWork][:lighting :performance :run]
[2:48:24][Make GridRayCast() cast the full LIGHTING_OCTAHEDRAL_RAYS_PER_TEXEL][:lighting]
[2:48:27][\~82% frame time (\~400,000,000 cycles) on ComputeLightPropagationWork][:lighting :performance :run]
[2:48:58][Make GridRayCast() cast half of the LIGHTING_OCTAHEDRAL_RAYS_PER_TEXEL][:lighting]
[2:49:12][Admire the cool red light bleed][:lighting :run]
[2:49:49][Make GridRayCast() double the RayWeight to compensate for the halved number of rays][:lighting]
[2:50:09][Admire the apparently structured light bleed bug][:lighting :run]
[2:51:28][Let GridRayCast() cast all the rays, at their appropriate weight][:lighting]
[2:51:51][Disable LIGHT_ATLAS_ASSERT][:lighting]
[2:52:10][\~28ms frame time][:lighting :performance :run]
[2:52:36][Disable HANDMADE_SLOW]
[2:52:48][\~24ms frame time][:lighting :performance :run]
[2:53:33][That's it for today][:speech]
[2:54:12][@gir33][Are the GPU shaders just lerping from the results that the CPU is doing?][:lighting]
[2:57:07][@gir33][Is that like a spherical harmonics encoding?][:lighting]
[3:01:02][That's it for today, with a glimpse into the future and reflections on the engine][:speech]
[3:02:42][@vaualbus][Can Z be re-added in an easier way now that the system is easier?][:lighting]
[3:05:13][That's it][:speech]
[/video]

View File

@ -0,0 +1,362 @@
[video output=day650 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Debugging Light Sampling Locations" vod_platform=youtube id=_CCjCvS88QM annotator=Miblo]
[0:02][Recap and set the stage for the day debugging our light contamination bug][:lighting :run]
[2:16][Describe ValidateTexelComponent()][:lighting :research]
[3:12][Make ValidateTexelComponent() consider a component greater than or equal to 0 to be valid, enabling LIGHT_ATLAS_ASSERT][:lighting]
[3:28][:Run without producing an invalid texel component][:lighting]
[4:06][Make ValidateTexelComponent() consider a component of between 0 and 100 to be valid][:lighting]
[4:21][:Run without producing an invalid texel component][:lighting]
[4:58][Force ValidateTexelComponent() to consider all components to be invalid][:lighting]
[5:05][Trap on SetLightAtlasTexels(), proving that ValidateTexelComponent() is being called][:lighting :run]
[5:17][Revert ValidateTexelComponent() to validate normally][:lighting]
[5:22][Traverse the orphanage and never produce an invalid texel component][:lighting :run]
[6:04][Restrict ValidateTexelComponent() to consider a component of between 0 and 10 to be valid][:lighting]
[6:15][:Run without producing an invalid texel component][:lighting]
[6:24][Restrict ValidateTexelComponent() to consider a component of between 0 and 1 to be valid][:lighting]
[6:42][Trap on PushLight() in an -O2 build][:lighting :run]
[6:53][Trap on VALIDATE_TEXEL() within PushLight() in an -Od build][:lighting :run]
[7:25][Expand ValidateTexelComponent() to consider a component of between 0 and 5 to be valid][:lighting]
[7:43][Trap on VALIDATE_TEXEL() within PushLight(), and inspect the Emission][:lighting :run]
[8:12][Reacquaint ourselves with StandardLightingPattern() and AddPieceLight()][:lighting :research]
[10:11][Restrict ValidateTexelComponent() to consider a component of between 0 and 1.1 to be valid][:lighting]
[10:25][Trap on VALIDATE_TEXEL() within PushLight()][:lighting :run]
[10:34][Make StandardLightingPattern() reduce the Emission value passed to AddPieceLight() from 10 to 1][:lighting]
[10:45][:Run without trapping][:lighting]
[10:57][:Run an -O2 build without trapping for a while, before trapping on PushLight() in UpdateAndRenderEntities()][:lighting]
[12:26][Revert StandardLightingPattern() to pass an Emission value of 10 to AddPieceLight()][:lighting]
[12:38][Trap on VALIDATE_TEXEL() within PushLight()][:lighting :run]
[12:48][Expand ValidateTexelComponent() to consider a component of between 0 and 10 to be valid][:lighting]
[12:54][Consider the possibility of this being an artifact of the way our system convects light][:lighting :run]
[13:44][Questions of our :lighting system: 1. Why do our lights have falloff? It's the inverse-square law, as an artifact of :sampling][:lighting :run]
[15:19][Questions of our :lighting system: 2. Why do we have over-brighting?][:lighting :run]
[16:04][Let GridRayCast() walk the grid all the way to the SPATIAL_GRID_NODE_TERMINATOR][:lighting]
[17:10][We still get over-brighting][:lighting :run]
[17:38][Make GridRayCast() walk the grid only eight steps, and zero out the HitRefColor if it gets that far][:lighting]
[18:24][We no longer get over-brighting indoors, but we do in some exteriors][:lighting :run]
[20:24][Make DebugDrawSpatialGrid() draw the occluders, and toggle on the call to it in UpdateLighting()][:"debug visualisation" :lighting]
[20:56][Over-brighting outdoors is affected by the player's position][:lighting :run]
[27:25][Toggle on DebugDrawOctahedralValues() and off DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[28:04][The interior lighting gets tinted green when the lighting bounds do not encompass the exterior wall][:lighting :run]
[29:59][Make StandardLightingPattern() colour the lights a non-random pure grey][:lighting]
[30:23][The interior lighting no longer gets tinted green][:lighting :run]
[31:13][We no longer get over-brighting outdoors][:lighting :run]
[32:15][Make StandardLightingPattern() colour the lights a more powerful grey][:lighting]
[32:29][We do get our over-brighting bug again][:lighting :run]
[33:11][Remove cruft from GridRayCast()][:lighting]
[34:55][Investigate why the light only leaks on the quarters][:lighting :research]
[36:47][Begin to illustrate our leaking case][:lighting :run]
[37:20][Plug the Qualcomm Keynote from CES 2013[ref
author=CES
title="2013 CES: Dr. Paul E. Jacobs, Qualcomm Inc. Keynote"
publisher=YouTube
url=https://youtu.be/Vn8qxSUbOko?t=430]][:research]
[42:23][Light leaking clues: 1. Exterior light probes beyond the wall unexpectedly pick up light][:lighting :run]
[45:18][Light leaking clues: 2. Enclosed light probes can suddenly pick up light][:lighting :run]
[46:20][Plan our light leak investigations][:lighting :run]
[51:21][@felkcraft][I don't know how that code works, but I see an x value be used for y variable called somethingY][:lighting]
[53:06][Reorient SteppingDeltaX as a negative offset in GridRayCast()][:lighting]
[54:49][@justslavic][Shouldn't there be a minus sign somewhere then?]
[55:16][Take a close look at our enclosed light probes suddenly picking up light][:lighting :run]
[58:31][Find the Owl][:admin]
[59:12][:Owl of Shame Parade]
[1:01:04][Light leaks below the world][:lighting :run]
[1:03:29][Reacquaint ourselves with GenerateApron()][:"procedural generation" :research]
[1:05:35][@tk_dev][Somewhere else Microsoft is receiving packages full of owls, but they don't know what they're for]
[1:05:43][Recommend Microsoft to build a giant Owl of Shame on their new campus[ref
site="Microsoft Stories"
page="New Redmond campus plan unveiled"
url=https://news.microsoft.com/announcement/new-redmond-campus-plan-unveiled/]][:research]
[1:06:32][@dedknd][They have the same bug]
[1:06:44][Recommend Microsoft to put the Owl of Shame on a rotating base[ref
site="Microsoft Stories"
page="New Redmond campus plan unveiled"
url=https://news.microsoft.com/announcement/new-redmond-campus-plan-unveiled/]][:research]
[1:07:45][Consider whether to enclose the world with floors or clamp the light ray cast's movement in Z][:lighting :research]
[1:11:27][Why not clamp the light ray cast's movement in Z][:lighting :run]
[1:12:48][Start to make GenerateApron() always generate ground cover][:"procedural generation"]
[1:15:20][Note the uneven ground outside generated rooms][:"procedural generation" :run]
[1:15:45][Make GenerateApron() reduce the vertical placement of overlapping entities by 1][:"procedural generation"]
[1:16:21][Light no longer leaks below the world][:lighting :"procedural generation" :run]
[1:17:26][Make GenerateApron() also reduce the vertical placement of overlapping entities besides trees][:"procedural generation"]
[1:17:50][The ground cover's vertical placement appears to be low][:"procedural generation" :run]
[1:17:58][Make GenerateApron() further decrease the vertical placement from 1 to 5][:"procedural generation"]
[1:18:09][The apron seems the same][:"procedural generation" :run]
[1:18:19][Make GenerateApron() further decrease the vertical placement from 5 to 10][:"procedural generation"]
[1:18:55][Nothing sticks out the bottom][:"procedural generation" :run]
[1:19:22][Put the P.z offsetting on its own line in GenerateApron() and build in -Od][:"procedural generation"]
[1:19:39][Break in to GenerateApron() and inspect its values][:"procedural generation" :run]
[1:23:03][Move the P.z offsetting below the Vol initialisation line in GenerateApron()][:"procedural generation"]
[1:23:31][Build in -O2]
[1:23:49][@fayyden][Is everything overlapped?]
[1:23:57][Overlapped entities now below the spatial partition][:"procedural generation" :run]
[1:24:13][Make GenerateApron() decrease the vertical placement less from 10 to 2][:"procedural generation"]
[1:24:24][Overlapped entities are back][:"procedural generation" :run]
[1:24:46][Overflow our entity count in EnsureRegionIsUnpacked()][:"entity system" :run]
[1:25:13][Temporarily increase MAX_SIM_REGION_ENTITY_COUNT from 2*8192 to 4*8192][:"entity system"]
[1:26:29][We report non-overlapped entities as overlapped][:"procedural generation" :run]
[1:27:04][Revert MAX_SIM_REGION_ENTITY_COUNT to 2*8192, and remove the overlapped entity offsetting in GenerateApron()][:"entity system" :"procedural generation"]
[1:27:23][Scour OverlappingEntitiesExist() and GenerateApron() for bugs][:"procedural generation" :research]
[1:29:07][Toggle on collision volume drawing in UpdateAndRenderEntities()][:"debug visualisation" :"entity system"]
[1:29:40][Our room boundaries are wrong][:"debug visualisation" :"entity system" :"procedural generation" :run]
[1:30:24][Make GenRoomVolume() offset the dimensions down by half][:"entity system" :"procedural generation"]
[1:31:58][Our room boundaries remain wrong][:"debug visualisation" :"entity system" :"procedural generation" :run]
[1:32:39][Fix GenRoomVolume() to offset the dimensions down by half a TileDim][:"entity system" :"procedural generation"]
[1:33:33][Our rooms are now correctly aligned][:"debug visualisation" :"entity system" :"procedural generation" :run]
[1:33:56][Our light still leaks][:lighting :"procedural generation" :run]
[1:35:12][Reacquaint ourselves with the occluder generation code][:"entity system" :"procedural generation" :research]
[1:39:56][Provoke the position-dependent interior light leak bug][:lighting :run]
[1:40:20][Make GenerateApron() call AddPieceOccluder() to generate a ceiling for each tile][:"entity system" :"procedural generation"]
[1:44:46][Traverse the orphanage][:"entity system" :"procedural generation" :run]
[1:45:04][Toggle off collision volume drawing in UpdateAndRenderEntities()][:"debug visualisation" :"entity system"]
[1:45:17][Successfully provoke the position-dependent interior light leak bug][:lighting :run]
[1:45:37][Toggle on DebugDrawSpatialGrid() and off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[1:46:16][With floors and ceilings, our enclosed light probes correctly no longer pick up light][:lighting :run]
[1:51:38][Make GenerateRoom() generate a ceiling light indoors][:"entity system" :"procedural generation"]
[1:52:57][Provoke the position-dependent interior light leak bug][:lighting :run]
[1:54:53][Disable StandardLightingPattern()][:lighting :"procedural generation"]
[1:55:51][The exterior area gets light from its ceiling tiles, but the interior does not][:lighting :"procedural generation" :run]
[1:56:42][Fix GenerateRoom() to generate the ceiling light outdoors, and the ceiling occluder indoors][:"entity system" :"procedural generation"]
[1:57:40][The interior now gets light][:lighting :"procedural generation" :run]
[1:59:15][Re-enable overhead light placement StandardLightingPattern()][:lighting :"procedural generation"]
[1:59:46][Briefly :run the game]
[1:59:51][Toggle off DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[2:00:06][Admire the lighting where it isn't buggy][:lighting :run]
[2:02:41][@alphalionmale][What graphics engine are you using?]
[2:03:02][The apron is not sealed][:lighting :"procedural generation" :run]
[2:03:46][@teamrandb][You could blame younger you]
[2:04:33][Wonder if the unsealed apron affects our light bleed bug][:lighting :"procedural generation" :run]
[2:05:10][@alphalionmale][Are trees 2D?]
[2:06:31][Ponder our position-dependent light feedback bug][:lighting :run]
[2:07:35][@salaryboi][New here, do you plan on making a full game to play or just focusing on the engine?]
[2:08:11][Plug [@naysayer88 Jonathan Blow]'s stream[ref
site=Twitch
page=j_blow
url=https://twitch.tv/j_blow]]
[2:08:33][Provoke our position-dependent light bleed bug outdoors][:lighting :run]
[2:09:10][@salaryboi][It could be educational to watch someone learn :"game design"]
[2:09:31][Z cannot be implicated in the position-dependent light bleed bug indoors][:lighting :run]
[2:12:01][@dieteetasse][Can the ray escape through the door into nothingness?][:lighting]
[2:13:43][@ablindorphan][Is there any way to prevent the wrapping, so it can't sample from the wrapped region?][:lighting :sampling]
[2:14:23][@felkcraft][I don't understand how bypassing some light barriers would lead to the kind of positive feedback loop we're seeing in some places][:lighting]
[2:14:35][The enclosed light bug is back][:lighting :run]
[2:14:57][The inverse-square law applies when hitting a light, but not when :sampling indirect light. Is that wrong?][:lighting :run]
[2:16:16][Make GridRayCast() zero out the HitEmission upon walking the distance][:lighting]
[2:16:48][Walls are oddly lit on every other shift of the lighting voxel][:lighting :run]
[2:17:58][@ablindorphan][Does this happen with pure white / pure red lights?][:lighting]
[2:18:12][Make StandardLightingPattern() colour the interior light pure \[5, 5, 5\] white][:lighting :"procedural generation"]
[2:18:21][The position-dependent interior light leak bug is gone][:lighting :run]
[2:18:41][Make StandardLightingPattern() colour the interior light a brighter \[7, 7, 7\] white][:lighting :"procedural generation"]
[2:18:58][The position-dependent interior light leak bug is back][:lighting :run]
[2:19:07][Make StandardLightingPattern() colour the interior light a dimmer \[6, 6, 6\] white][:lighting :"procedural generation"]
[2:19:21][The position-dependent interior light leak bug remains][:lighting :run]
[2:19:45][Make StandardLightingPattern() colour the interior light a dimmer \[5, 5, 5\] white][:lighting :"procedural generation"]
[2:19:58][The position-dependent interior light leak bug is gone][:lighting :run]
[2:21:26][Consider the value sensitivity of our position-dependent light leak bug][:lighting :run]
[2:22:19][@spotnag][Why is the light bottom-left in that room brighter than the others?][:lighting]
[2:23:39][Inspect the ray casting on the brighter bottom-left tile][:"debug visualisation" :lighting :run]
[2:26:21][@felkcraft][The light source box looks bigger than one tile, like it's 1.0 and not "tile sized"]
[2:26:52][Toggle on drawing of the lights in UpdateAndRenderEntities()][:"debug visualisation" :lighting]
[2:27:07][Check out our lights][:"debug visualisation" :lighting :run]
[2:27:26][Make UpdateAndRenderEntities() draw the lights at their correct size][:"debug visualisation" :lighting]
[2:29:08][Check out our lights][:"debug visualisation" :lighting :run]
[2:30:00][@spacenaming][There was a TODO in CalcBasePForOffset that said it still needed to be implemented]
[2:30:10][@spotnag][The brighter one is closer to other lights that are behind walls. Could it be that the walls are not stopping it picking up light? So it has itself plus the other two next to it the other side of the walls?][:lighting]
[2:31:31][CalcBasePForOffset() doesn't matter][:"entity system" :"procedural generation" :research]
[2:32:11][We have position-dependent brightening in the non-traversable outdoors][:lighting :run]
[2:36:03][Scour GridRayCast() for the ramifications of hitting tTerminate and zeroing HitRefColor][:lighting :research]
[2:38:54][Check out the rays cast in the brighter non-traversable outdoors][:lighting :run]
[2:39:23][Toggle on DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[2:39:42][The light apparently comes through the wall][:lighting :run]
[2:41:20][Scour GridRayCast() for bugs in getting the light atlas][:lighting :research]
[2:44:22][Reproduce our position-dependent brightening][:lighting :run]
[2:44:53][Rename Grid to AtlasGrid in GridRayCast()[ref
author=CES
title="2013 CES: Dr. Paul E. Jacobs, Qualcomm Inc. Keynote"
publisher=YouTube
url=https://youtu.be/Vn8qxSUbOko?t=430]][:lighting]
[2:48:05][Check our region alignments][:"debug visualisation" :lighting :run]
[2:48:51][PushLightingRenderValues() draws the HotVoxelRect in cyan and the SpatialGrid in green][:"debug visualisation" :lighting :research]
[2:50:10][Our light :sampling reads and writes are misaligned][:lighting :run]
[2:51:57][Vote for a quick break][:admin]
[2:52:52][:afk]
[2:56:43][Return][:admin]
[2:57:08][@thesandvichmaker][No! Brain-parasite music!]
[2:57:17][Fanfare][:admin]
[2:57:58][@tk_dev][Maybe you should let Cody handle the second part of the stream, then you don't need a break]
[2:58:45][@dedknd][@niftywifty *Will Smith approaching...*]
[3:01:53][@thesandvichmaker][Will the [~hero Handmade Hero] awards have exciting moments? Maybe you can invite and then slap a Microsoft employee]
[3:02:51][Investigate our :sampling readwrite misalignment][:lighting :research]
[3:04:38][@ryanfleury][Keep! My struct's name! Out your fuckin' mouth!!!]
[3:04:58][The GetCellCenterP() call in ComputeLightPropagationWork() is horse poop][:lighting :research]
[3:05:17][We're eating Peanut Butter Pretzels from Costco][:admin]
[3:06:15][@ablindorphan][Would you like me to talk to Mr Costco for you?]
[3:06:28][Change ComputeLightPropagationWork() to set BoxCenterP using GetCellBounds().Min][:lighting]
[3:08:30][The octahedral value drawings are now positioned wrong][:"debug visualisation" :lighting :run]
[3:08:54][Rename BoxCenterP to CastFromP in ComputeLightPropagationWork()][:lighting]
[3:09:40][Fix DebugDrawOctahedralValues() to position the drawings at the Bounds.Min][:"debug visualisation" :lighting]
[3:10:49][We have light probes unable to pick up light around the perimeter][:"debug visualisation" :lighting :run]
[3:12:00][Our light leaking is now more pronounced][:"debug visualisation" :lighting :run]
[3:13:43][Reacquaint ourselves with the atlas grid and spatial grid creation code in UpdateLighting() and MakeLightAtlas()][:lighting :research]
[3:17:44][Make UpdateLighting() shrink the atlas grid by one in all dimensions][:lighting]
[3:18:40][Our light probes now fill the atlas grid][:lighting :run]
[3:20:18][Make UpdateLighting() position the light atlas at half a VoxCellDim in Z][:lighting]
[3:21:11][The light atlas is too high][:lighting :run]
[3:21:42][Stop UpdateLighting() from repositioning the light atlas in Z][:lighting]
[3:21:52][The light atlas is a little too low][:lighting :run]
[3:22:13][Make UpdateLighting() offset the light atlas upwards in Z by half a VoxCellDim][:lighting]
[3:22:23][The light atlas is better positioned and aligned][:lighting :run]
[3:23:30][Reacquaint ourselves with the light sample readwrite alignment in PushLightingRenderValues() and SampleLighting()][:lighting :research :sampling]
[3:27:58][Prevent SumLight() from offsetting VoxR by -0.5 in all dimensions, and make SampleLighting() clamp our lookups within the lighting voxel][:lighting :sampling]
[3:30:34][Our floors are now lit][:lighting :run]
[3:32:03][Scour GridRayCast() for :sampling bugs][:lighting :research]
[3:36:07][Our debug ray picking is now broken][:"debug system" :lighting :run]
[3:37:03][Fix FullCast() to clamp the ray picker's atlas index to the full cell count][:"debug system" :lighting]
[3:37:35][Our debug ray picking remains broken][:"debug system" :lighting :run]
[3:38:16][Temporarily prevent FullCast() from clamping the ray picker's atlas index][:"debug system" :lighting]
[3:38:28][Our debug ray picking remains broken][:"debug system" :lighting :run]
[3:38:45][Let FullCast() clamp the ray picker's atlas index][:"debug system" :lighting]
[3:38:53][Investigate our ray picking bug][:"debug system" :lighting :research]
[3:39:24][Make UpdateLighting() compute an offset AtlasGridCellCount to prevent the light map from being reset every frame][:lighting]
[3:40:29][Our debug ray picking works again][:"debug system" :lighting :run]
[3:41:04][Inspect our rays to determine that they are offset][:"debug visualisation" :lighting :run]
[3:43:32][Scour FullCast() for alignment bugs][:lighting :research]
[3:46:47][Make FullCast() map the light probes into the spatial grid, using GetIndexForP()][:lighting]
[3:48:03][Briefly :run the game][:lighting]
[3:48:13][Remove AtlasToSpatialGridIndexOffset from lighting_solution][:"data structure" :lighting]
[3:49:06][We still have casting bugs][:lighting :run]
[3:49:43][@said6289][Why is there no timer?]
[3:50:02][Start the timer][:admin]
[3:50:20][Glance at UpdateLighting() for bugs][:lighting :research]
[3:51:05][Consider the lighting bounds placement to be correct][:lighting :run]
[3:51:57][Scour UpdateLighting() and FullCast() for bugs][:lighting :research]
[3:54:01][Rename the VoxCenterP argument to LightProbeP in FullCast()][:lighting]
[3:54:17][Scour GridRayCast() for bugs][:lighting :research]
[3:55:33][Delete CellDim4 and related code in GridRayCast()][:lighting]
[3:56:38][Scour GridRayCast() for bugs (cont.)][:lighting :research]
[3:57:57][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[3:58:11][The spatial partition and lighting voxel are oddly aligned][:lighting :run]
[3:59:18][Make UpdateLighting() offset the spatial grid by half a VoxCellDim in x and y][:lighting]
[4:00:08][Inspect our rays to determine that they seem pretty good][:"debug visualisation" :lighting :run]
[4:01:44][Our lighting is more stable, but the lighting voxel slides relative to the spatial grid][:"debug visualisation" :lighting :run]
[4:02:36][Investigate our lighting voxel sliding bug][:lighting :research]
[4:09:29][Make UpdateLighting() set the HotDim to the AtlasGrid's dimensions][:lighting]
[4:11:03][Our lighting now flickers, and has black spots][:lighting :run]
[4:11:55][Revert the HotDim initialisation in UpdateLighting()][:lighting]
[4:12:10][The flicker and black spots have gone][:lighting :run]
[4:12:44][Toggle on DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[4:13:22][The octahedrons don't shift, only their values alter][:lighting :run]
[4:14:47][Toggle on DebugDrawSpatialGrid() and off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[4:14:55][The spatial grid looks pretty solid[ref
author=CES
title="2013 CES: Dr. Paul E. Jacobs, Qualcomm Inc. Keynote"
publisher=YouTube
url=https://youtu.be/Vn8qxSUbOko?t=430]][:"debug visualisation" :lighting :run]
[4:15:37][Toggle on DebugDrawOctahedralValues() and off DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[4:15:49][Eyeball the light probes and realise that our scale is wrong][:"debug visualisation" :lighting :run]
[4:16:17][Reacquaint ourselves with the scaling in PushLightingRenderValues() and SumLight()][:lighting :research]
[4:21:07][Make SumLight() contract the LIGHT_LOOKUP_VOXEL_DIM by 1 in all dimensions when setting VoxR][:lighting]
[4:21:34][Our scaling now seems right][:"debug visualisation" :lighting :run]
[4:21:54][Toggle off drawing of the lights in UpdateAndRenderEntities() and DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[4:22:24][The light seems pretty stable][:lighting :run]
[4:23:56][Consider aligning the lighting region such that the camera remains well within it][:lighting :research]
[4:24:43][The lighting region is biased][:lighting :run]
[4:25:28][Increase the LIGHT_LOOKUP_VOXEL_DIM_X from 24 to 28, and LIGHT_LOOKUP_VOXEL_DIM_Y from 16 to 20][:lighting]
[4:25:52][The lighting region remains biased][:lighting :run]
[4:26:38][Toggle off the camera bounds drawing in UpdateAndRenderWorld()][:camera :"debug visualisation"]
[4:27:32][Traverse the orphanage as if playing the game][:run]
[4:28:39][Decrease tUpdateBlend from 1 to 15/60 in UpdateLighting()][:lighting]
[4:29:18][Traverse the orphanage][:run]
[4:29:27][Move the ray debug drawing out of the way in UpdateLighting()][:"debug visualisation" :lighting]
[4:29:47][Traverse the orphanage as if playing the game, and admire the :lighting][:run]
[4:30:24][Toggle off LIGHT_ATLAS_ASSERT and GRID_RAY_CAST_DEBUGGING][:lighting]
[4:31:05][\~41ms per frame][:lighting :performance :run]
[4:32:08][Toggle off HANDMADE_INTERNAL and HANDMADE_SLOW, and stub out DIAGRAM_SetOrigin() and RenderDiagrams()][:"debug visualisation"]
[4:34:13][Feel the :performance][:lighting :run]
[4:34:29][Delete WalkTableOffset from light_sample_directions][:"data structure" :lighting :metaprogramming]
[4:35:30][Run hhsphere with an octahedron texel count and ray per texel of 8][:admin :lighting]
[4:36:33][Feel the :performance with 8 rays per texel][:lighting :run]
[4:36:49][Toggle on HANDMADE_INTERNAL and stub out world and world_position][:"data structure"]
[4:37:56][\~23ms per frame][:lighting :performance :run]
[4:38:18][Toggle on HANDMADE_SLOW]
[4:38:27][\~26ms per frame][:lighting :performance :run]
[4:38:47][Determine to toggle off the diffuse blend][:lighting :research]
[4:39:21][\~29ms per frame][:lighting :performance :run]
[4:39:27][Toggle off the diffuse blend in ComputeLightPropagationWork()][:lighting]
[4:39:32][\~29ms per frame][:lighting :performance :run]
[4:39:54][Toggle on the diffuse blend in ComputeLightPropagationWork()][:lighting]
[4:40:03][\~29ms per frame][:lighting :performance :run]
[4:40:13][Toggle off FullCast() in ComputeLightPropagationWork()][:lighting]
[4:40:21][\~16ms per frame][:lighting :performance :run]
[4:40:42][Toggle on FullCast() in ComputeLightPropagationWork()][:lighting]
[4:40:52][Admire our excellent interior :lighting][:run]
[4:41:59][Consider specially handling light probes embedded in geometry][:lighting :run]
[4:43:32][Toggle on the player's light in UpdateAndRenderWorld()][:lighting]
[4:44:50][Lights produce a glow when eclipsing a light probe][:lighting :run]
[4:45:19][Toggle on DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[4:45:29][Our player's light occludes the light probes, removing light from the system][:lighting :run]
[4:45:49][Darken the player's light from 10 to 5, and increase its size in Z from 0.5 to 1][:lighting]
[4:46:13][Check out the player's light][:lighting :run]
[4:46:26][Revert the player's light size, and elevate it from 2 to 2.5][:lighting]
[4:46:42][The player's light still occludes the light probe][:lighting :run]
[4:46:44][Elevate the player's light from 2.5 to 3][:lighting]
[4:46:50][The player's light no longer occludes the light probe][:lighting :run]
[4:46:57][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[4:47:06][Traverse the orphanage admiring the light][:lighting :run]
[4:47:17][Brighten the player's light from 5 to 8][:lighting]
[4:47:24][Traverse the orphanage admiring the light][:lighting :run]
[4:47:56][Toggle off StandardLightingPattern()][:lighting :"procedural generation"]
[4:48:26][Illustrate the checkerboard patterning from the :sampling sphere][:lighting :run]
[4:49:42][Prevent GridRayCast() from zeroing out HitRefColor and HitEmission upon walking the distance][:lighting]
[4:50:34][See no difference in the :lighting, but admire it nevertheless][:performance :run]
[4:51:41][Switch GridRayCast() from the sample table lookup to :sampling in a white noise pattern][:lighting]
[4:55:28][The light flickers with this white noise :sampling][:lighting :run]
[4:56:01][Make GridRayCast() cast 32 rays][:lighting :sampling]
[4:56:19][The light goes over-bright][:lighting :run :sampling]
[4:56:25][Make GridRayCast() cast 32 rays correctly weighted][:lighting :sampling]
[4:57:22][The light flickers less with 32 rays][:lighting :run :sampling]
[4:58:17][Decrease the RayCount from 32 to 16 in GridRayCast()][:lighting :sampling]
[4:58:26][The light flickers more with 16 rays][:lighting :run :sampling]
[4:58:30][Increase the RayCount from 16 to 64 in GridRayCast()][:lighting :sampling]
[4:58:39][The light barely flickers with 64 rays][:lighting :run :sampling]
[4:59:02][Decrease the RayCount from 64 to 8 in GridRayCast(), and decrease tUpdateBlend from 15/60 to 6/60 in UpdateLighting()][:lighting :sampling]
[4:59:31][The light looks pretty good][:lighting :run :sampling]
[5:00:26][Toggle on the room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[5:00:43][We barely notice flicker, and can get over-brighting indoors with many lights][:lighting :run]
[5:03:01][Toggle off the player's light in UpdateAndRenderWorld()][:lighting]
[5:03:12][@ponkkiz][I think the darker one looked awesome][:lighting]
[5:03:23][The interior does not over-brighten without the player light][:lighting :run]
[5:03:35][Toggle off AddPattern() on the MainRoom in CreateOrphanage()][:lighting :"procedural generation"]
[5:04:04][Traverse the orphanage to the unlit main room][:lighting :run]
[5:04:23][Make MoveEntity() move the entity and then leave][:"entity system"]
[5:05:43][Hit our DiagramDepth == 0 assertion in RenderDiagrams()][:"debug system" :run]
[5:05:55][Make MoveEntity() call DIAGRAM_End() after moving the entity][:"debug system" :"entity system"]
[5:06:38][Make MoveEntity() return after moving the entity :"entity system"]
[5:06:49][Our glove now moves with us][:"entity system" :run]
[5:07:10][Make AddPlayer() call AddPieceLight() on the Glove][:"entity system" :lighting]
[5:09:09][Our light convects too much][:lighting :run]
[5:09:16][Make GridRayCast() zero out HitRefColor and HitEmission upon walking the distance][:lighting]
[5:09:53][Our light still convects too much][:lighting :run]
[5:09:59][Prevent GridRayCast() from zeroing out HitRefColor and HitEmission upon walking the distance][:lighting]
[5:10:25][Darken the glove's light from 5 to 1 in AddPlayer()][:"entity system" :lighting]
[5:10:26][Take our dim green glove light into the main room][:lighting :run]
[5:10:47][Brighten the glove's light from 1 to 3 in AddPlayer()][:"entity system" :lighting]
[5:10:57][Our light feeds back when we stand still][:lighting :run]
[5:12:45][Prevent FullCast() from blacking out light probes inside geometry][:lighting]
[5:13:32][Our light no longer blacks out when a light probe is inside geometry][:lighting :run]
[5:14:14][Consider our over-brighting bug][:lighting :run]
[5:15:01][Let FullCast() cast rays from inside geometry][:lighting]
[5:15:23][The light goes over-bright][:lighting :run :sampling]
[5:15:33][Consider our over-brighting bug][:lighting :research :sampling]
[5:17:06][Make FullCast() blacken rather than cast rays from inside geometry][:lighting]
[5:18:04][Determine to add an exposure curve and make all lights between 0 and 1 brightness][:lighting :research]
[5:18:45][@thesandvichmaker][@handmade_hero I like this super basic neutral exposure curve as a default[ref
site=Desmos
page="Natural shoulder tonemap"
url=https://www.desmos.com/calculator/zsxj2jbvdb]][:lighting]
[5:19:40][@teamrandb][@handmade_hero Greetings [@cmuratori Casey]! May you update SendOwl code download, please? It seems stuck on Day 346 with no updates]
[5:20:26][One last look at our light contamination][:lighting :run]
[5:20:52][@floorislava][handmade_hero_646_source.zip is what I'm showing]
[5:21:01][One last look at our light contamination (cont.)][:lighting :run]
[5:21:47][End it here for today][:speech]
[5:22:01][@teamrandb][Sorry, I wrote it wrong. 646. But 646 is February 28th]
[5:22:46][Call it there][:speech]
[/video]

View File

@ -0,0 +1,239 @@
[video output=day651 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Fixing Light Feedback" vod_platform=youtube id=h-ueZgo_Txk annotator=Miblo]
[0:00][Recap and set the stage for the day looking into light transport][:blackboard :lighting]
[2:55][Light Transport][:blackboard :lighting]
[3:14][Light Transport: 1. Throwing a light source in a scene, :sampling and the inverse-square law][:blackboard :lighting :sampling]
[16:59][Light Transport: 2. Our lack of a reflectance equation that distributes energy fairly without adding energy to the system][:blackboard :lighting :sampling]
[27:44][Light Transport: Distributing reflected light fairly][:blackboard :lighting :sampling]
[35:14][Drink of water][:admin]
[35:18][:afk]
[35:32][Return and clean the board][:admin]
[36:57][Light Transport: Photon counting, Collection 1 (Direct)][:blackboard :lighting :sampling]
[43:36][Light Transport: Photon counting, Collection 2 (Reflected)][:blackboard :lighting :sampling]
[53:16][Light Transport: Energy conservation and collection of light from other probes][:blackboard :lighting :sampling]
[55:18][:afk]
[55:25][Return][:admin]
[55:35][@spacenaming][@handmade_hero Just wanted to let you know you clipped once during the lightboard session (at the word "max" funnily enough), the rest was fine]
[55:41][Reduce the lightboard scene's audio][:admin]
[56:32][Energy conservation confusion][:lighting :research]
[57:04][@nickito97][So the problem is the probe is measuring the "flow" of light through the probe, and the wall next to he probe is using that value to reflect, despite the fact that "flow" can keep going and be reused by other probes, generating more light from nothing?][:lighting]
[59:09][@recyrillic][We could calculate the amount emitted and the amount received and artificially dampen the emission the next frame. But I am not sure that would fix it as we still would have one frame of latency][:lighting]
[1:00:26][Consider reading about light probes][:lighting :research]
[1:04:15][@evuntech][Propagating light info between light probes doesn't make much sense to me. I think you'd want to interpolate rather than sharing info between them][:lighting]
[1:05:31][Recall the original paper we read on light probes[ref
author=CES
title="2013 CES: Dr. Paul E. Jacobs, Qualcomm Inc. Keynote"
publisher=YouTube
url=https://youtu.be/Vn8qxSUbOko?t=430]][:lighting :research]
[1:07:15][Consult 'Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields'[ref
title="Dynamic Diffuse Global Illumination with Ray-Traced Irradiance Fields"
author="Jean-Philippe Guertin, Derek Nowrouzezahrai, Morgan McGuire"
url=http://jcgt.org/published/0008/02/01/]][:lighting :research]
[1:14:05][Reacquaint ourselves with ComputeLightPropagationWork() and BuildDiffuseLightMaps()][:lighting :research]
[1:16:57][Consider ordering Real-Time Rendering[ref
site="Real-Time Rendering"
url=http://www.realtimerendering.com/]][:lighting :rendering :research]
[1:18:27][Consult 'Real-Time Global Illumination using Precomputed Light Field Probes'[ref
author="Morgan McGuire, Michael Mara, Derek Nowrouzezahrai, David Luebke"
title="Real-Time Global Illumination using Precomputed Light Field Probes"
url=https://casual-effects.com/research/McGuire2017LightField/]][:lighting :research]
[1:29:48][Demo the light feedback][:lighting :run]
[1:30:10][Darken the glove's light from 3 to 1 in AddPlayer()][:"entity system" :lighting]
[1:30:21][The light does not feed back][:lighting :run]
[1:31:19][Brighten the glove's light from 1 to 2 in AddPlayer()][:"entity system" :lighting]
[1:31:28][The light slowly feeds back][:lighting :run]
[1:31:51][Darken the glove's light from 2 to 1 in AddPlayer()][:"entity system" :lighting]
[1:32:11][The light does not feed back, but why?][:lighting :run]
[1:33:42][@drzool][1.1 * 1.1 = larger than original]
[1:34:48][Consider fixing the occlusion bug][:lighting :run]
[1:35:43][Reacquaint ourselves with the bilinear :filtering code in GridRayCast()][:lighting :research]
[1:39:19][Reacquaint ourselves with our surface colours][:lighting :research]
[1:43:22][Brighten the glove's light from 1 to 1.25 in AddPlayer()][:"entity system" :lighting]
[1:44:15][The light does not feed back][:lighting :run]
[1:44:34][Brighten the glove's light from 1.25 to 1.3 in AddPlayer()][:"entity system" :lighting]
[1:44:48][The light appears not to feed back][:lighting :run]
[1:45:09][Brighten the glove's light from 1.3 to 1.5 in AddPlayer()][:"entity system" :lighting]
[1:45:18][The light appears not to feed back][:lighting :run]
[1:45:30][Brighten the glove's light from 1.5 to 1.75 in AddPlayer()][:"entity system" :lighting]
[1:45:39][The light slowly feeds back][:lighting :run]
[1:47:08][@mariusorc][Q: Is it possible that the color dampening hits some negative values and adds to the :lighting instead?]
[1:48:18][@vaualbus][But did we always have this problem? Like, can be the removal of Z or the walking grid make this happen?][:lighting]
[1:48:41][Decrease tUpdateBlend from 6/60 to 1/60 in UpdateLighting()][:lighting]
[1:48:52][The light appears not to feed back][:lighting :run]
[1:49:12][Brighten the glove's light from 1.75 to 2 in AddPlayer()][:"entity system" :lighting]
[1:49:22][The light slowly feeds back][:lighting :run]
[1:49:34][Increase tUpdateBlend from 1/60 to 6/60 in UpdateLighting()][:lighting]
[1:49:38][The light quickly feeds back][:lighting :run]
[1:50:46][Consider how to progress, possibly applying an exposure curve][:lighting :research]
[1:52:33][Consult LearnOpenGL's HDR article[ref
site=LearnOpenGL
page=HDR
url=https://learnopengl.com/Advanced-Lighting/HDR] for a simple exposure curve][:lighting :research]
[1:53:42][Make CompileZBiasProgram() clamp SurfaceReflect in a single call][:lighting]
[1:53:59][That seems fine][:lighting :run]
[1:54:07][Make CompileZBiasProgram() apply Reinhard tone mapping to the SurfaceReflect][:lighting]
[1:54:55][The light feeds back][:lighting :run]
[1:55:32][Remove Reinhard tone mapping from SurfaceReflect in CompileZBiasProgram()][:lighting]
[1:55:48][@immow][Are beginner questions okay?]
[1:56:03][Eyeball our over-brighting bug][:lighting :run]
[1:57:25][Make GridRayCast() zero out HitRefColor and HitEmission upon walking the distance][:lighting]
[1:58:32][The light feeds back][:lighting :run]
[1:58:53][Make GridRayCast() only zero out HitRefColor and HitEmission upon hitting the SPATIAL_GRID_NODE_TERMINATOR][:lighting]
[1:59:11][The light feeds back][:lighting :run]
[1:59:19][Revert our changes to GridRayCast()][:lighting]
[2:00:12][@vaualbus][Q: Could it be :sampling errors? Like aliasing or some sort of things like that? Also maybe we are not always dealing with normalized numbers, and in the equation we should count normalization values?][:lighting]
[2:02:13][@mallesbixie][Last time I watched, there was sus copy pasta code at the TransferPPSAccum line endings. Can we peak there again?]
[2:02:47][@mallesbixie][Yeah, there, 0 as last args]
[2:03:10][Describe the shuffler code in GridRayCast()][:lighting :research]
[2:08:27][Consider our definition of the light transfer problem to be wrong][:lighting :run]
[2:09:05][Consider working through the light transfer problem on the light board][:lighting :research]
[2:09:58][@mindmark42][What is the normal storing thing the paper[ref
author="Morgan McGuire, Michael Mara, Derek Nowrouzezahrai, David Luebke"
title="Real-Time Global Illumination using Precomputed Light Field Probes"
url=https://casual-effects.com/research/McGuire2017LightField/] was talking about?][:lighting]
[2:10:08][Toggle on DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[2:10:37][Describe our light probe octahedral values][:"debug visualisation" :lighting :run]
[2:11:23][Darken the glove's light from 2 to 1 in AddPlayer()][:"entity system" :lighting]
[2:11:46][Describe our light probe octahedral values, without feedback][:"debug visualisation" :lighting :run]
[2:13:26][Toggle on GRID_RAY_CAST_DEBUGGING][:lighting]
[2:13:37][Describe the paper's[ref
author="Morgan McGuire, Michael Mara, Derek Nowrouzezahrai, David Luebke"
title="Real-Time Global Illumination using Precomputed Light Field Probes"
url=https://casual-effects.com/research/McGuire2017LightField/] storage of hit surface normal][:lighting :run]
[2:16:34][Toggle off room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[2:17:23][Our glove alone does not contaminate][:lighting :run]
[2:17:48][Make CompileZBiasProgram() multiply the SurfaceReflect by 10][:lighting]
[2:18:45][Our glove is brighter][:lighting :run]
[2:18:56][Make CompileZBiasProgram() multiply the SurfaceReflect by 100][:lighting]
[2:19:01][Our glove is brighter still, and does not feed back][:lighting :run]
[2:19:28][Toggle on room lights in StandardLightingPattern(), and reduce their intensity from 10 to 0.1][:lighting :"procedural generation"]
[2:20:04][Our world is the brightness we'd like, and the light does not feed back][:lighting :run]
[2:20:17][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[2:20:36][Our world is the brightness we'd like, and the light does not feed back][:lighting :run]
[2:22:06][Darken the glove's light from 1 to 0.2 in AddPlayer()][:"entity system" :lighting]
[2:22:31][Our :lighting looks basically correct][:run]
[2:22:53][Darken the moonlight from 0.2 to 0.025 in GenerateApron()][:lighting :"procedural generation"]
[2:23:26][The exterior light is still quite bright][:lighting :run]
[2:23:30][Darken the moonlight from 0.025 to 0.01 in GenerateApron()][:lighting :"procedural generation"]
[2:23:37][The exterior light is maybe about right][:lighting :run]
[2:23:41][Darken the moonlight from 0.01 to 0.005 in GenerateApron()][:lighting :"procedural generation"]
[2:23:49][The light looks as we'd like][:lighting :run]
[2:24:54][@sagian2005][Gorgeous light that we don't understand][:lighting]
[2:25:09][An unanticipated portion of the system is working as a percentage][:lighting :run]
[2:26:11][Determine to address our occluded light probe darkening problem][:lighting :research]
[2:26:40][Toggle on DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[2:27:06][Illustrate our darkened occluded light probe][:lighting :run]
[2:27:37][Make DebugDrawSpatialGrid() colour the leaves with their RefColor][:"debug visualisation" :lighting]
[2:29:09][The spatial grid leaves are all white][:"debug visualisation" :lighting :run]
[2:29:24][Make DebugDrawSpatialGrid() account for Emission when colouring the leaves][:"debug visualisation" :lighting]
[2:30:05][Illustrate our darkened embedded light probes][:lighting :run]
[2:31:19][Describe the code that blackens embedded light probes in FullCast()][:lighting :research]
[2:31:59][Prevent FullCast() from touching embedded light probes][:lighting]
[2:32:13][Light probes no longer darken when occluded by the glove, but neither do they receive its full light contribution][:lighting :run]
[2:33:00][Consider running the occlusion check on every sample][:lighting :research]
[2:35:18][Let FullCast() cast rays from embedded light probes][:lighting]
[2:35:36][The light looks good][:lighting :run]
[2:36:37][Document the embedded light probe ray casting][:lighting]
[2:37:24][The light leaks through walls][:lighting :run]
[2:38:45][Make FullCast() distinguish between emitters and occluders, making only the latter contribute to the IsInside check][:lighting]
[2:42:18][The light no longer leaks through walls][:lighting :run]
[2:43:39][@psarokroketa][Wouldn't IsEmission <= Zero work?][:lighting]
[2:43:44][Reorient the Mask computation around IsOccluder in FullCast()][:lighting]
[2:44:05][Light probes remain not directly lit by overlapping emitters][:lighting :run]
[2:46:07][Toggle off DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[2:46:28][Our octahedron directions may be nonsense][:"debug visualisation" :lighting :run]
[2:47:01][DebugDrawOctahedralValues() isn't nonsense][:"debug visualisation" :lighting :research]
[2:47:32][Consider writing our emission values into the light probes as a pre-pass][:"debug visualisation" :lighting :run]
[2:48:35][@coffeeb4code][Curious what the total size of [~hero Handmade Hero] is (clientside)]
[2:48:52][Consider writing our emission values into the light probes as a pre-pass (cont.)][:"debug visualisation" :lighting :run]
[2:49:40][@coffeeb4code][The binary]
[2:49:55][1 MiB executable size][:admin]
[2:50:39][@coffeeb4code][Without assets? That's so small]
[2:51:18][Consider writing our emission values into the light probes as a pre-pass (cont.)][:"debug visualisation" :lighting :run]
[2:52:45][@gusfrehse][I'd say to the left][:lighting]
[2:54:12][Consider writing the emission value of light volumes into light probes proportional to their overlap][:lighting :run]
[2:58:48][Consider writing the emission value of light volumes into light probes stochastically][:lighting :run]
[3:00:07][Reacquaint ourselves with our use of the specular light atlas][:lighting :research]
[3:03:54][Rename LightDepthSampler to SpecularSampler in the OpenGL renderer][:lighting]
[3:04:15][Consider sampling from the specular map rather than the diffuse map][:lighting :research]
[3:05:39][Yearn for the ability in C++ to #include a file as a string][:language :rant :speech]
[3:07:19][Remove GetIrradiance()][:lighting]
[3:08:41][@wocket251][I think std\:\:embed got killed sadly][:language]
[3:12:28][@youngsterglenn][Enough of those committees and you can work towards eliminating all bad decisions][:language]
[3:13:37][@skaman512][The problem is about embedding a shader in your code? I think inside a constexpr you can read a file and return an array (and do it at compile time)][:language]
[3:14:00][@ryanfleury][I just always have my own path for #embed in my metaprogram, and throw my shaders into metacode][:language :metaprogramming]
[3:14:23][Reacquaint ourselves with SampleLighting()][:lighting :research]
[3:15:12][@nedboulter][If you don't like C++ why are you using C++?][:language]
[3:15:46][Reacquaint ourselves with specular and diffuse map usage in SampleLighting()][:lighting :research]
[3:17:31][Check out our light][:lighting :run]
[3:17:47][Toggle from radial to our manual bilinear interpolation in SampleLighting()][:lighting]
[3:18:02][Our light looks the same][:lighting :run]
[3:18:18][Toggle off our manual interpolation path in CompileZBiasProgram()][:lighting]
[3:18:25][Our light looks the same][:lighting :run]
[3:18:58][Double-check that we call SampleLighting()][:lighting :research]
[3:19:51][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[3:19:56][Our light interpolation looks a little squarer][:lighting :run]
[3:20:53][Toggle on our radial interpolation in SampleLighting9)][:lighting]
[3:20:57][Our light looks the same][:lighting :run]
[3:21:03][Try making SampleLighting() colour the light red][:lighting]
[3:21:25][We're reloading shaders][:lighting :run]
[3:21:30][Let SampleLighting() work as normal, toggling from our radial to the regular bilinear interpolation][:lighting]
[3:21:46][Consider the regular bilinear sampling to be fine][:lighting :run]
[3:22:17][Remove our fancier interpolation code from SampleLighting() and use v3 rather than v4][:lighting]
[3:23:49][Our light looks the same][:lighting :run]
[3:23:59][Fix indentation of SumLight()][:lighting]
[3:24:57][@psarokroketa][Is there really no way to indent multiple lines together in ~4coder?]
[3:25:42][Rename LightColorSampler to DiffuseSampler in the OpenGL renderer][:lighting]
[3:26:18][Our light looks the same][:lighting :run]
[3:26:25][Make SampleLighting() use the SpecularSampler][:lighting]
[3:26:49][Our light now looks unpleasant and shiny][:lighting :run]
[3:27:29][Reacquaint ourselves with the reflection directionality in SumLight()][:lighting :research]
[3:28:48][@psarokroketa][So you can just say move these 10 lines one to the left without it messing it up? This sounds painful]
[3:29:51][Check out our specular light][:lighting :run]
[3:30:09][Switch SumLight() to use the reflection vector][:lighting]
[3:30:50][Check out our actual specular light][:lighting :run]
[3:32:04][@recyrillic][@handmade_hero You can use a macro like '#define shader_code(a) #a' and then on 'char *shader = shader_code(<insert shader here>);' the <shader code> gets auto indented. At least that works for me. (Sorry if you read the previous one and ignored it on purpose)]
[3:33:07][Introduce OctFrom() for SumLight() to call and compute both the specular and diffuse atlases to pass to SampleLighting()][:lighting]
[3:36:34][Our light kind of looks right][:lighting :run]
[3:37:04][Make SampleLighting() sum together the specular and diffuse atlases][:lighting]
[3:37:26][Check out our half-and-half specular / diffuse lighting][:lighting :run]
[3:37:46][Set up SampleLighting() to interpolate between our specular and diffuse atlases using a Material][:lighting]
[3:38:46][Check out our light][:lighting :run]
[3:39:23][#define EmbedShader()][:language]
[3:40:55][Hit a "Shader validation failed" error][:language :run]
[3:42:00][Scour our EmbedShader() calls for syntax errors][:language :research]
[3:42:51][@anelysian][I think the preprocessor isn't going to preserve the #if's]
[3:43:45][Try removing the #if's from our EmbedShader() calls][:language]
[3:44:09][:Run without hitting a "Shader validation failed" error][:language :run]
[3:44:21][Revert our introducing of EmbedShader()][:language]
[3:45:16][Consider our light to be too bright][:lighting :run]
[3:45:47][Prevent CreateOrphanage() from adding light outdoors][:lighting :"procedural generation"]
[3:46:38][Our moonlight is still a little too bright][:lighting :"procedural generation" :run]
[3:47:20][Darken the moonlight from 0.2 to 0.01 in GenerateRoom()][:lighting :"procedural generation"]
[3:47:45][Our moonlight seems better][:lighting :"procedural generation" :run]
[3:48:36][Decrease tUpdateBlend from 6/60 to 3/60 in UpdateLighting()][:lighting]
[3:48:57][Our light doesn't look very flickery][:lighting :run]
[3:49:23][Decrease tUpdateBlend from 3/60 to 1/60 in UpdateLighting()][:lighting]
[3:49:28][Our light still doesn't flicker][:lighting :run]
[3:49:42][Increase tUpdateBlend from 1/60 to 20/60 in UpdateLighting()][:lighting]
[3:49:51][Our light flickers][:lighting :run]
[3:50:03][Decrease tUpdateBlend from 20/60 to 12/60 in UpdateLighting()][:lighting]
[3:50:16][Our light is a little flickery][:lighting :run]
[3:53:00][Increase RayCount from 8 to 16 in GridRayCast()][:lighting]
[3:53:12][Our light minimally flickers][:lighting :run]
[3:54:36][Determine to tackle forward-rasterisation next week][:lighting :research]
[3:54:59][Toggle off room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[3:55:12][Admire our spooky orphanage][:lighting :run]
[3:56:22][Make CreateOrphanage() put a Snake in BedroomA, and darken the light from 5 to 1 in SnakePattern()][:lighting :"procedural generation"]
[3:58:24][Watch the snake in BedroomA][:lighting :"procedural generation" :run]
[3:58:51][Darken the light from 1 to 0.25 in SnakePattern()][:lighting :"procedural generation"]
[3:59:02][@i_am_seabass][I think the glove needs some glowy light emitting particle effects now][:lighting :"particle system"]
[3:59:08][Watch the snake get stuck in the corner][:lighting :"procedural generation" :run]
[3:59:26][Make CreateOrphanage() put Snakes in BedroomB and BedroomC][:lighting :"procedural generation"]
[3:59:57][Our snakes lock up in the corner][:lighting :"procedural generation" :run]
[4:00:30][Prevent CreateOrphanage() from putting snakes in the bedrooms, and make StandardLightingPattern() create dimmer and randomly coloured room lights][:lighting :"procedural generation"]
[4:01:08][Admire our fantastic light][:lighting :run]
[4:02:01][Plan to fix the overlapped emitter and light probe dimming bug, and maybe bundle our rays][:lighting :speech]
[4:02:53][@mindmark42][So we're just ignoring the feedback issue?][:lighting]
[4:04:37][@wylem][Is the feedback thing just because the lighting has a temporal element, kind of turning it into a system where you have energy going in each frame and damping from absorption? And if the energy going in exceeds the damping, you get feedback?][:lighting]
[4:06:34][That's it for today][:speech]
[/video]

View File

@ -0,0 +1,254 @@
[video output=day652 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Stochastic Ray Origins" vod_platform=youtube id=SuvSMkf9-i8 annotator=Miblo]
[0:00][Recap and set the stage for the day handling light emitters overlapping light probes][:lighting :speech]
[2:41][@comrademaria][Q: Scene is wrong]
[3:01][Illustrate our overlapped light emitter-probe dimming bug][:lighting :run]
[3:56][Note how FullCast() doesn't cast rays from overlapped light probes][:lighting :research]
[4:28][Toggle on DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[4:49][Illustrate our overlapped light emitter-probe dimming bug][:"debug visualisation" :lighting :run]
[8:12][Possible overlapped emitter-probe solutions: 1. Rasterise light into overlapped probes as a pre-pass][:"debug visualisation" :lighting :run]
[10:52][Possible overlapped emitter-probe solutions: 2. Jitter sampling locations][:"debug visualisation" :lighting :run]
[11:12][Possible overlapped emitter-probe solutions: 3. Disallow overlapping of emitters and probes][:"debug visualisation" :lighting :run]
[13:51][Consider how to handle overlapped light emitters and probes, admiring our specular lighting][:"debug visualisation" :lighting :run]
[17:06][Toggle off DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[17:14][Consider trying jittering the sampling locations][:lighting :run]
[18:52][Possible overlapped emitter-probe solutions: 4. Permit rays to hit geometry they're inside of][:"debug visualisation" :lighting :research]
[19:54][Reacquaint ourselves with the intersection testing code in GridRayCast()][:lighting :research]
[23:54][Let GridRayCast() cast rays from inside everything][:lighting]
[24:19][Embedded probes now see light][:lighting :run]
[25:19][Enable GridRayCast() to track if a light probe was inside geometry][:lighting]
[26:56][Embedded probes still see light][:lighting :run]
[27:51][Toggle on DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[27:59][Light probes do not gather light from overlapping emitters][:"debug visualisation" :lighting :run]
[28:28][Our light probe's rays must be hitting the overlapping emitter][:lighting :research]
[29:36][@psarokroketa][That tInside variable doesn't seem to be used, in case you assume it is?][:lighting]
[29:53][Investigate why GridRayCast() doesn't light up our overlapped light probe][:lighting :research]
[33:23][Make GridRayCast() clamp the tMin to 0 and above][:lighting]
[34:29][Light probes gather light from overlapping emitters, but too brightly][:"debug visualisation" :lighting :run]
[36:07][Toggle on room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[36:26][We happily lack light bleed][:lighting :run]
[37:08][Comment tInside as intentionally not used in GridRayCast()][:lighting]
[38:24][Note our overly bright eclipsed probes, also with square artifacting][:lighting :run]
[41:44][Consider jittering light ray origins in X and Y][:lighting :research]
[43:36][Weld FullCast() and GridRayCast() together][:lighting]
[46:38][We :run just as before][:lighting]
[46:54][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[47:05][Consider jittering light ray origins in X and Y][:lighting :run]
[47:45][Rename Pick to DebugPick in FullCast()][:lighting]
[49:57][Determine to jitter light ray origins in X and Y][:lighting :run]
[50:47][Make FullCast() jitter light ray origins in X and Y][:lighting]
[52:45][Our :lighting system is still doing something][:run]
[53:35][Make FullCast() keep jittered rays within their original tile][:lighting]
[54:55][Our :lighting looks a little wrong][:run]
[55:42][Consider how to proceed][:lighting :research]
[56:53][Reduce the JitterRadius in FullCast()][:lighting]
[57:04][We have a little bit of light bleed][:lighting :run]
[58:06][Consider what could be wrong with the jittered :lighting][:run]
[59:08][@steadygoa][Not backface culling rays][:lighting]
[59:38][Enable GRID_RAY_CAST_DEBUGGING][:lighting]
[1:00:12][Our debug overlay is now over-bright][:lighting :run :ui]
[1:00:32][Our ray casting isn't obviously wrong][:"debug visualisation" :lighting :run]
[1:01:52][Make FullCast() draw our ray's starting location][:"debug visualisation" :lighting]
[1:02:56][Check out a ray's starting locations][:"debug visualisation" :lighting :run]
[1:04:33][Change FullCast() to clamp the tRay to 0 as tClampedCompare, to retain the negatives][:lighting]
[1:06:32][Our embedded ray casting looks technically correct][:"debug visualisation" :lighting :run]
[1:08:47][The jittering looks okay, but doesn't behave well when moving between probes][:lighting :run]
[1:10:55][@steadygoa][It looks like water reflecting light rays][:lighting]
[1:11:29][Make SampleLighting() use a pure diffuse material][:lighting]
[1:11:34][Demo our pure diffuse light][:lighting :run]
[1:12:01][Make SampleLighting() use a pure specular material][:lighting]
[1:12:08][Demo our pure specular light][:lighting :run]
[1:13:12][Make SampleLighting() use a half-and-half specular / diffuse material][:lighting]
[1:13:25][Demo our half-and-half specular / diffuse light][:lighting :run]
[1:14:01][Illustrate our square artifacting around overlapped light probes][:lighting :run]
[1:15:07][Make AddPlayer() shrink the glove's light from 0.5 to 0.25][:lighting :"procedural generation"]
[1:15:52][Our glove's smaller light almost disappears][:lighting :run]
[1:17:25][Make AddPlayer() brighten the glove's light from 0.2 to 0.5][:lighting :"procedural generation"]
[1:17:32][Our glove's smaller but brighter light still almost disappears][:lighting :run]
[1:20:25][Make AddPlayer() enlarge the glove's light from 0.25 to 2][:lighting :"procedural generation"]
[1:20:39][Our glove's larger light works][:lighting :run]
[1:21:06][Make AddPlayer() darken the glove's light from 0.5 to 0.125][:lighting :"procedural generation"]
[1:21:29][Our glove's larger and darkened light looks just right][:lighting :run]
[1:21:58][Make AddPlayer() darken the glove's light from 0.125 to 0.05][:lighting :"procedural generation"]
[1:22:07][Our glove's larger and darkened light looks as expected][:lighting :run]
[1:23:53][Make AddPlayer() shrink the glove's light from 2 to 1, and brighten it from 0.05 to 0.1][:lighting :"procedural generation"]
[1:24:08][Our glove's light remains][:lighting :run]
[1:25:12][Make AddPlayer() shrink the glove's light from 1 to 0.5][:lighting :"procedural generation"]
[1:25:25][Our glove's light remains][:lighting :run]
[1:26:00][Make AddPlayer() shrink the glove's light from 0.5 to 0.4][:lighting :"procedural generation"]
[1:26:12][Our glove's light blinks][:lighting :run]
[1:28:03][Consider stratifying the light sampling][:lighting :run]
[1:29:25][@deggua][Is this because it's so small the probability of a sample ray intersecting the emissive source starts to become heavily affected by the random rays' distribution and whether they actually hit the emissive object? Seems like some kind of temporal averaging or a finer resolution grid would help][:lighting]
[1:29:58][Clean out cruft from UpdateLighting()][:lighting]
[1:33:10][We still :run][:lighting]
[1:33:12][Make FullCast() stratify the samples into a 4×4 grid][:lighting]
[1:36:46][Our glove's light still blinks][:lighting :run]
[1:38:55][Temporarily make FullCast() seed its random series with a constant value, to fix the rays][:lighting :prng]
[1:39:24][Our glove's light still pulsates with fixed rays, but why?][:lighting :run]
[1:44:06][Scour FullCast() for sources of noise][:lighting :prng :research]
[1:45:07][@mtsmox][Maybe the position of the glove, the bobbing, turn that off?]
[1:45:11][The glove doesn't bob][:lighting :run]
[1:45:38][Increase tUpdateBlend from 12/60 to 1 in UpdateLighting()][:lighting]
[1:46:24][Our glove's light blinks vigorously][:lighting :run]
[1:48:16][@fat_dratini][Runaway NaNs]
[1:48:46][Our glove's light blinks vigorously (cont.)][:lighting :run]
[1:49:46][Toggle off room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[1:50:03][Only overlapped light probes have the blinking bug][:lighting :run]
[1:51:10][Temporarily prevent GridRayCast() from casting rays from inside geometry][:lighting]
[1:51:41][Our light still blinks, but less vigorously][:lighting :run]
[1:52:09][Let GridRayCast() cast rays from inside geometry][:lighting]
[1:52:14][Consider how to approach our blinking bug][:lighting :research]
[1:54:14][@snoringtortoise][Could you turn on NaN exceptions so if we hit a NaN the program will halt?]
[1:54:19][Check our tUpdate and JitterRadius][:lighting :research]
[1:55:21][Decrease the JitterRadius multiplier from 0.45 to 0.4 in FullCast()][:lighting]
[1:55:30][Our light still blinks][:lighting :run]
[1:55:34][Decrease the JitterRadius multiplier from 0.4 to 0.1 in FullCast()][:lighting]
[1:55:36][Our light blinks more sporadically][:lighting :run]
[1:56:10][Increase the JitterRadius multiplier from 0.1 to 0.45 in FullCast()][:lighting]
[1:56:31][Determine to get snacks and enable NaN exceptions][:speech]
[1:56:53][@fnaarp][Maybe try just setting tUpdateBlend to 1 in both clauses of that if?]
[1:57:02][Remove the tUpdateBlend modification branch from UpdateLighting(), and remove Accumulating, AccumulationCount and FrameOdd from lighting_solution][:lighting]
[1:57:35][Our light continues to blink][:lighting :run]
[1:58:09][Determine to get snacks and enable NaN exceptions][:speech]
[1:58:47][Grab snacks][:admin]
[1:58:57][:afk]
[2:03:06][Return with snacks][:admin]
[2:03:42][@snoringtortoise][[@cmuratori Casey]: Just wondering if removing the (tMin < tMax) expression from the Mask calculation will have an effect? That part of the expression was added this stream][:lighting]
[2:04:11][@snoringtortoise][[@cmuratori Casey]: If the ray can be negative, then couldn't tMin be > tMax some of the time?][:lighting]
[2:04:42][@fnaarp][Why'd it change from a throb to a blink?][:lighting]
[2:05:04][Demo the blinking light][:lighting :run]
[2:05:12][Toggle on room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[2:05:22][Demo the blinking, with stable lighting][:lighting :run]
[2:06:14][Revert FullCast() to seed its random series randomly][:lighting :prng]
[2:06:33][Demo the blinking with noisy lighting][:lighting :run]
[2:07:14][@yuika_lamonting][The blinking?][:lighting]
[2:07:31][Demo the flickery lighting (cont.)][:lighting :run]
[2:09:51][@fnaarp][So temporal averaging made the blink into a throb, got it][:lighting]
[2:10:41][Wonder why the glove light blinks when small enough][:lighting :run]
[2:11:07][Make AddPlayer() enlarge the glove's light from 0.4 to 0.5][:lighting :"procedural generation"]
[2:11:36][Our glove's larger light rarely blinks][:lighting :run]
[2:12:09][@mtsmox][Can you see if the gameplay speed is related by slowing down the clock?]
[2:12:21][Slowing the timestep stops the light from blinking (even after speeding it back up again)][:run]
[2:14:48][Toggle on DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[2:14:51][Our light probe is suspiciously positioned in Z relative to the glove][:lighting :run]
[2:15:57][Toggle off DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[2:16:16][Halve the JitterRadius along Z, and make FullCast() jitter light ray origins in Z][:lighting]
[2:16:41][Our glove's light flickers more sporadically][:lighting :run]
[2:17:31][Increase the JitterRadius multiplier from 0.45 to 0.5 in FullCast()][:lighting]
[2:17:44][Our glove's light still flickers sporadically][:lighting :run]
[2:18:56][Decrease tUpdateBlend from 1 to 12/60 in UpdateLighting()][:lighting]
[2:18:59][The glove's light now barely flickers][:lighting :run]
[2:20:05][Light leaks to the outdoors][:lighting :run]
[2:21:13][Admire the :lighting, and consider putting in an exposure curve and a notion of brightness (for bloom)][:run]
[2:23:47][Make AddPlayer() shrink the glove's light from 0.4 to 0.25, and brighten it from 0.1 to 0.2][:lighting :"procedural generation"]
[2:24:08][The glove's smaller light varies more][:lighting :run]
[2:24:39][Make AddPlayer() enlarge the glove's light from 0.25 to 0.75, and darken it from 0.2 to 0][:lighting :"procedural generation"]
[2:25:03][Our glove's light is dark][:lighting :run]
[2:25:10][Make AddPlayer() brighten the glove's light from 0 to 0.1][:lighting :"procedural generation"]
[2:25:28][The glove's larger light is pretty stable][:lighting :run]
[2:26:26][Consider adding spheres][:geometry :lighting :run]
[2:31:36][Make AddPlayer() shrink the glove's light from 0.75 to 0.25][:lighting :"procedural generation"]
[2:31:46][Our glove's smaller light is dimmer][:lighting :run]
[2:31:59][Make AddPlayer() brighten the glove's light from 0.1 to 1][:lighting :"procedural generation"]
[2:32:11][Our glove's small and bright light is not too noisy][:lighting :run]
[2:33:19][Consider how to proceed][:lighting :run]
[2:34:07][Real-time global illumination: General purpose engines (using global illumination only for secondary indirect lighting) vs ours (using it for both direct and indirect lighting)][:lighting :run]
[2:39:27][@mtsmox][How do the other engines "skip" the direct light and only use secondary bounces?][:lighting]
[2:41:28][@fnaarp][Crazy idea - since all your surfaces are xy / xz / yz planes, could you look at a circle around a projection of the light source onto the surface rather than spherical intersection?][:lighting]
[2:43:06][@deggua][So you either have to do all sphere lights or all AABB lights?][:geometry :lighting]
[2:43:12][Describe the changes to FullCast() required to support spherical lights][:geometry :lighting :research]
[2:45:59][@spacenaming][But shouldn't a small enough box give a spherical falloff as well?][:lighting]
[2:46:31][Consider how to proceed][:lighting :run]
[2:47:53][Increase RayCount from 16 to 256 in GridRayCast()][:lighting]
[2:48:20][The light still doesn't look great around the light source][:lighting :run]
[2:48:49][Decrease RayCount from 256 to 16 in GridRayCast()][:lighting]
[2:48:59][Our glove's light is noisier][:lighting :run]
[2:49:06][Make AddPlayer() shrink the glove's light from 0.25 to 0.1][:lighting :"procedural generation"]
[2:49:21][:Run the game][:lighting]
[2:49:24][Make AddPlayer() shrink the glove's light from 0.1 to 0.05][:lighting :"procedural generation"]
[2:49:28][Our glove's light is barely visible][:lighting :run]
[2:49:48][Increase RayCount from 16 to 1024 in GridRayCast()][:lighting]
[2:49:56][Our glove's light is barely visible][:lighting :run]
[2:50:59][Make AddPlayer() brighten the glove's light from 1 to 10, and decrease the RayCount from 1024 to 16 in GridRayCast()][:lighting :"procedural generation"]
[2:51:23][Our light flickers][:lighting :run]
[2:51:43][Increase RayCount from 16 to 1024 in GridRayCast()][:lighting]
[2:51:51][Our light no longer flickers][:lighting :run]
[2:53:08][Decrease RayCount from 1024 to 16 in GridRayCast(), and make AddPlayer() brighten the glove's light from 10 to 20][:lighting]
[2:53:21][Our light flickers][:lighting :run]
[2:53:45][Increase RayCount from 16 to 1024 in GridRayCast()][:lighting]
[2:53:49][Our light no longer flickers][:lighting :run]
[2:54:12][Make AddPlayer() brighten the glove's light from 20 to 100, and decrease the RayCount from 1024 to 64 in GridRayCast()][:lighting :"procedural generation"]
[2:54:34][Our :performance has degraded][:lighting :run]
[2:54:51][Decrease RayCount from 64 to 16 in GridRayCast()][:lighting]
[2:55:01][Our light flickers][:lighting :run]
[2:55:21][Increase RayCount from 16 to 1024 in GridRayCast()][:lighting]
[2:55:27][Our light no longer flickers][:lighting :run]
[2:55:57][Make AddPlayer() enlarge the glove's light from 0.05 to 0.4 and darken it from 100 to 1, and decrease RayCount from 1024 to 16 in GridRayCast()][:lighting :"procedural generation"]
[2:56:33][Our glove's light has a square falloff][:lighting :run]
[2:56:48][Increase RayCount from 16 to 1024 in GridRayCast()][:lighting]
[2:56:55][Our glove's light still has a square falloff][:lighting :run]
[2:57:17][Decrease RayCount from 1024 to 16 in GridRayCast()][:lighting]
[2:57:27][Our glove's light still has a square falloff][:lighting :run]
[2:57:55][@mtsmox][Could you then also remove the temporal smooth?][:lighting]
[2:58:08][Increase tUpdateBlend from 12/60 to 1 in UpdateLighting()][:lighting]
[2:58:12][Our light flickers][:lighting :run]
[2:58:20][Increase RayCount from 16 to 1024 in GridRayCast()][:lighting]
[2:58:26][Our glove's light still has a square falloff][:lighting :run]
[2:59:03][Decrease RayCount from 1024 to 16 in GridRayCast()][:lighting]
[2:59:21][Our light flickers][:lighting :run]
[2:59:39][Start to enable FullCast() to handle spherical lights][:lighting]
[3:02:27][Switch to the lightboard][:admin]
[3:03:56][Sphere vs. Ray][:blackboard :collision :geometry :lighting :mathematics]
[3:08:42][Sphere vs. Ray intersection equation, Take 1][:blackboard :collision :geometry :lighting :mathematics]
[3:16:36][Sphere vs. Ray intersection equation, Take 2][:blackboard :collision :geometry :lighting :mathematics]
[3:19:59][Switch to the code][:admin]
[3:20:12][@sagian2005][Do we need the coordinates? Or do we just need to know if it intersects?][:collision :geometry :lighting :mathematics]
[3:20:51][Reacquaint ourselves with the sphere intersection code in CastSampleRays() from ray.cpp][:collision :geometry :lighting :mathematics :research]
[3:24:32][SQRTPS() and DIVPS() are on ports 0, and cost 3 cycles[ref
site=uops.info
url=https://uops.info/table.html]][:performance :research]
[3:27:39][Enable FullCast() to handle spherical lights based on CastSampleRays() from ray.cpp][:lighting]
[3:42:12][Introduce SquareRoot()][:mathematics]
[3:42:41][Enable FullCast() to handle spherical lights based on CastSampleRays() from ray.cpp (cont.)][:lighting]
[3:44:58][Our sphere code is running][:lighting :run]
[3:45:04][Toggle off the spherical intersection in FullCast()][:lighting]
[3:46:05][Our glove's light has a square falloff][:lighting :run]
[3:46:18][Toggle on the spherical intersection in FullCast()][:lighting]
[3:46:26][Our light is doing something different][:lighting :run]
[3:46:36][Enable GridBuildSpatialPartition() to handle spherical lights][:lighting]
[3:50:23][Our glove's light looks less square][:lighting :run]
[3:51:01][Decrease tUpdateBlend from 1 to 12/60 in UpdateLighting()][:lighting]
[3:51:07][Our glove's light looks even less square][:lighting :run]
[3:51:33][Increase RayCount from 16 to 1024 in GridRayCast()][:lighting]
[3:51:58][Our glove's light is centred wrong][:lighting :run]
[3:52:47][Decrease RayCount from 1024 to 16 in GridRayCast(), and make AddPlayer() darken the glove's light from 1 to 0.25][:lighting :"procedural generation"]
[3:53:10][Our glove's light is centred wrong][:lighting :run]
[3:54:13][Double-check the spherical light code in GridBuildSpatialPartition() and GridRayCast()][:lighting :research]
[3:58:25][Eyeball our spherical light][:lighting :run]
[3:59:10][Make AddPlayer() add a light to the hero's head rather than the glove][:lighting :"procedural generation"]
[4:00:08][We may be detecting intersections where the sphere doesn't actually touch][:lighting :run]
[4:01:50][@deggua][Probably NaN I would guess]
[4:02:25][Fix the RootTerm computation in GridRayCast(), and test it before square rooting it][:lighting]
[4:04:42][Our spherical light looks better][:lighting :run]
[4:05:41][Make AddPlayer() brighten the glove's light from 0.25 to 0.5][:lighting :"procedural generation"]
[4:06:03][Our light still looks a bit square][:lighting :run]
[4:06:40][Increase RayCount from 16 to 1024 in GridRayCast()][:lighting]
[4:06:53][Our light still looks a bit square][:lighting :run]
[4:08:26][Disable LIGHTS_ARE_SPHERES][:lighting]
[4:08:40][Our light looks brighter and more prominently square][:lighting :run]
[4:09:31][@sagian2005][Yeah, it looks like it's just being clipped to the voxel somehow][:lighting]
[4:09:50][Enable LIGHTS_ARE_SPHERES][:lighting]
[4:09:55][Our light looks dimmer and less square][:lighting :run]
[4:11:29][Decrease RayCount from 1024 to 16 in GridRayCast()][:lighting :"procedural generation"]
[4:11:41][Our light trails behind us][:lighting :run]
[4:11:59][Increase tUpdateBlend from 12/60 to 20/60 in UpdateLighting()][:lighting]
[4:12:22][Our light trails less, but flickers][:lighting :run]
[4:12:48][Increase tUpdateBlend from 20/60 to 1 in UpdateLighting()][:lighting]
[4:12:54][Our light flickers, and seems to have a frame of lag][:lighting :run]
[4:14:20][Increase tUpdateBlend from 1 to 12/60 in UpdateLighting()][:lighting]
[4:14:31][Determine to make the light interpolation less square][:lighting :run]
[4:15:31][Disable LIGHTS_ARE_SPHERES][:lighting]
[4:15:37][Our light looks brighter and more prominently square][:lighting :run]
[4:16:08][That's it for today, with a plug of Molly Movie Club[ref
site="Molly Movie Club"
url=https://www.mollymovieclub.com/]][:speech]
[/video]

View File

@ -0,0 +1,205 @@
[video output=day653 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Adding a Filmic Response Curve" vod_platform=youtube id=4U33fh8Lj5w annotator=Miblo]
[0:00][Recap and set the stage for the day improving the quality of single bright light sources][:lighting :run]
[1:07][Decrease RayCount from 16 to 8 in GridRayCast()][:lighting :"procedural generation"]
[1:24][Smooth framerate with good light everywhere other than around small fast-moving light sources][:lighting :run]
[2:35][Diffuse gather looks quite good, and the flicker is good enough][:lighting :run]
[5:19][Consider writing light into overlapping probes as a forward pass][:lighting :run]
[7:26][Toggle on DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[7:39][Our light source is lower than expected][:"debug visualisation" :lighting :run]
[8:27][Make AddPlayer() elevate the head light from 0 to 0.5][:lighting :"procedural generation"]
[9:10][Our light is higher up][:lighting :run]
[9:19][Make AddPlayer() elevate the head light from 0.5 to 1][:lighting :"procedural generation"]
[9:27][Our light is less square][:lighting :run]
[10:51][Toggle on DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[11:01][Glimpse our spatial grid and octahedral values][:"debug visualisation" :lighting :run]
[11:05][Toggle off DebugDrawOctahedralValues() and DebugDrawSpatialGrid() in UpdateLighting()][:"debug visualisation" :lighting]
[11:12][Our light is still a bit square][:lighting :run]
[11:39][Make AddPlayer() decrease the head light's intensity from 0.5 to 0.25, and add the glove light][:lighting :"procedural generation"]
[11:55][Our glove light has a fair bit of lag, and it's still a bit square][:lighting :run]
[13:30][@nomad_pixel][Wait, I grabbed some water. Is this with tone mapping now?][:lighting]
[14:08][Make AddPlayer() elevate the glove light from 0 to 0.5][:lighting :"procedural generation"]
[14:30][Consider the possibility of repairing the squareness][:lighting :run]
[15:05][Consider doing filmic tone mapping[ref
site="Krzysztof Narkowicz"
page="ACES Filmic Tone Mapping Curve"
url=https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/][ref
site=Desmos
page="Graphic Calculator"
url=https://www.desmos.com/calculator][ref
site="Filmic Games"
page="Filmic Tonemapping Operators"
url=https://web.archive.org/web/20160211234532/filmicgames.com/archives/75]][:lighting :research]
[29:55][Introduce ACESFilm()[ref
site="Krzysztof Narkowicz"
page="ACES Filmic Tone Mapping Curve"
url=https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/] and remove IrradiancePack() and stale code from SumLight()][:lighting]
[34:03][Check out our "before tone mapping" :lighting][:run]
[34:17][Make the fragment shader in CompileZBiasProgram() call ACESFilm()][:lighting]
[35:37][Our light already looks a lot more dramatic, but still square][:lighting :run]
[37:27][Enable LIGHTS_ARE_SPHERES][:lighting]
[37:32][The lights dim, but remain square][:lighting :run]
[37:57][Disable LIGHTS_ARE_SPHERES][:lighting]
[38:04][Consider rasterising light into overlapped probes as a pre-pass][:lighting :run]
[41:13][@drzool][How about jittering the light probe positions?]
[42:20][Admire the :lighting besides the squareness][:run]
[43:54][Toggle off room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[44:07][Admire the indirect :lighting with only one light source][:run]
[44:34][Increase RayCount from 8 to 64 in GridRayCast()][:lighting :"procedural generation"]
[44:52][The light now has very little flicker][:lighting :run]
[45:11][Decrease RayCount from 64 to 16 in GridRayCast()][:lighting :"procedural generation"]
[45:13][Consider rasterising light into overlapped probes as a pre-pass][:lighting :run]
[46:50][Toggle on DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[46:52][Our light fall-off has a hard edge not explained by linear interpolation][:"debug visualisation" :lighting :run]
[49:29][Make SampleLighting() use a pure diffuse material][:lighting]
[50:00][Our diffuse map doesn't quite have the same problem][:lighting :run]
[50:21][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[50:28][Our light is still more square than we'd like][:lighting :run]
[50:38][Make SampleLighting() use a pure specular material][:lighting]
[50:45][Our small moving light is very hard edged in the specular map][:lighting :run]
[50:56][Make DebugDrawOctahedralValues() draw the SpecAtlas values, toggling it on in UpdateLighting()][:"debug visualisation" :lighting]
[51:23][Our light probes pick up a far more gradual fall-off than appears][:"debug visualisation" :lighting :run]
[53:37][Reacquaint ourselves with SumLight()][:lighting :research]
[1:01:10][Check out our current light][:"debug visualisation" :lighting :run]
[1:01:22][Prevent SumLight() from shrinking LIGHT_LOOKUP_VOXEL_DIM by 1 when computing VoxR][:lighting]
[1:01:30][Our :lighting shifts][:run]
[1:02:57][Revert SumLight() to shrink LIGHT_LOOKUP_VOXEL_DIM by 1 when computing VoxR][:lighting]
[1:03:36][Hunt for a corresponding minus 1 in FullCast()][:lighting :research]
[1:06:19][The light fall-off's hardness is influenced by the reflection angle][:lighting :run]
[1:08:20][Make SampleLighting() use a pure diffuse material][:lighting]
[1:08:26][Check out our pure diffuse light][:lighting :run]
[1:09:53][Consider changing the interpolation of the octahedral map][:lighting :run]
[1:11:38][Introduce Mestre() for SumLight() to use][:lighting]
[1:19:07][Our light is more circular][:lighting :run]
[1:20:00][Toggle off DebugDrawOctahedralValues() in UpdateLighting()][:"debug visualisation" :lighting]
[1:20:10][Our more circular light is nicer, but maybe still not quite right][:lighting :run]
[1:21:27][Toggle on room lights in StandardLightingPattern()][:lighting :"procedural generation"]
[1:21:44][Our more circular light is better than the alternative][:lighting :run]
[1:22:59][@frizi09][I still believe this might be just an artifact of too low voxel resolution, and what we see is actually expected given the current constraints][:lighting]
[1:24:22][Comment out the Mestre() calls in SumLight()][:lighting]
[1:24:41][Our light looks great barring the squareness][:lighting :run]
[1:24:55][Determine to place a known point of light in the system][:lighting :research]
[1:26:30][Determine to make ComputeLightPropagationWork() further slice up the work for better :threading][:lighting]
[1:28:07][Make FullCast() hard set the TransferPPS of all light probes in a radial pattern][:lighting]
[1:31:34][Our light fall-off does not look radial][:lighting :run]
[1:31:56][Multiply the distance between the origin and light probe by 0.1 to try and prevent more distant probes from zeroing out][:lighting]
[1:32:05][Our light fall-off looks radial][:lighting :run]
[1:32:07][Multiply the distance between the origin and light probe by 0.25][:lighting]
[1:32:16][Our light fall-off looks more blocky][:lighting :run]
[1:33:38][Make the fragment shader in CompileZBiasProgram() remove a guessed 0.1 from the SurfaceReflect][:lighting]
[1:34:11][Our light is blown out][:lighting :run]
[1:34:20][Make the fragment shader in CompileZBiasProgram() clamp SurfaceReflect to 0][:lighting]
[1:35:11][Our light fall-off is now circular][:lighting :run]
[1:35:29][Decrease the SurfaceReflect light floor removal from 0.1 to 0.01][:lighting]
[1:35:41][Our light fall-off is a little blocky again][:lighting :run]
[1:35:48][Increase the SurfaceReflect light floor removal from 0.01 to 0.05][:lighting]
[1:36:02][Our light fall-off is circular][:lighting :run]
[1:36:18][Comment out the hardcoded TransferPPS in FullCast()][:lighting]
[1:36:29][Our light falls to black][:lighting :run]
[1:37:26][Comment out the SurfaceReflect light floor removal in the fragment shader][:lighting]
[1:37:36][Our light is back][:lighting :run]
[1:37:49][Check Clamp0Inf() for bugs][:lighting :research]
[1:38:08][Decrease the SurfaceReflect light floor removal from 0.05 to 0][:lighting]
[1:38:21][Our light remains][:lighting :run]
[1:38:26][Increase the SurfaceReflect light floor removal from 0 to 0.01][:lighting]
[1:38:35][Our light darkens considerably][:lighting :run]
[1:38:41][Decrease the SurfaceReflect light floor removal from 0.01 to 0.001][:lighting]
[1:38:50][Our light brightens somewhat][:lighting :run]
[1:39:07][Increase the SurfaceReflect light floor removal from 0.001 to 0.01][:lighting]
[1:39:19][Our light fall-off is very circular][:lighting :run]
[1:39:44][@leemyy][Considering this is supposed to be specular, I find it odd that the region at full brightness is so large][:lighting]
[1:39:57][Make SampleLighting() use a pure specular material][:lighting]
[1:40:04][Our specular light fall-off remains circular][:lighting :run]
[1:40:25][Make SampleLighting() use a pure diffuse material][:lighting]
[1:40:28][Applying a natural floor enables our light to fall off radially][:lighting :research]
[1:43:00][Decrease the SurfaceReflect light floor removal from 0.01 to 0.0001][:lighting]
[1:43:14][Our light fall-off is square again][:lighting :run]
[1:43:23][Increase the SurfaceReflect light floor removal from 0.0001 to 0.01][:lighting]
[1:43:33][Our light fall-off is circular, but the solution is too dark][:lighting :run]
[1:43:58][Remove the SurfaceReflect light floor removal][:lighting]
[1:44:18][@pfizzyenator][Is the ACESFilm() function contributing to the badness?][:lighting]
[1:44:27][The light with ACESFilm()][:lighting :run]
[1:44:33][Remove the ACESFilm() call][:lighting]
[1:44:46][The light without ACESFilm()][:lighting :run]
[1:44:55][Reinsert the ACESFilm() call][:lighting]
[1:45:02][The light with ACESFilm()][:lighting :run]
[1:45:27][Consider the light pretty reasonable][:lighting :run]
[1:47:00][Without flooring, linear interpolation won't cut it][:lighting :research]
[1:47:39][@frizi09][Would it be practical to up the voxel resolution a bit? Just to see the comparison][:lighting]
[1:48:38][Double the LIGHT_LOOKUP_VOXEL_DIM_X and LIGHT_LOOKUP_VOXEL_DIM_Y][:lighting]
[1:49:01][Our :lighting region is larger][:"debug visualisation" :run]
[1:49:23][Make UpdateLighting() halve the VoxCellDim in all dimensions][:lighting]
[1:50:04][Hit an out-of-bounds assert in GridBuildSpatialPartition()][:lighting :run]
[1:50:28][Make UpdateLighting() retain the full VoxCellDim in Z][:lighting]
[1:51:03][Hit an out-of-bounds assert in GridBuildSpatialPartition()][:lighting :run]
[1:51:33][Scour UpdateLighting() for sources of our out-of-bounds lookup][:lighting :research]
[1:52:22][Run an -Od build until hitting our IsInBounds() assertion in FlatIndexFrom()][:lighting :run]
[1:55:10][Investigate our IsInBounds() assertion hit in FlatIndexFrom()][:lighting :run]
[1:56:57][Remove the Z loops from GridBuildSpatialPartition()][:lighting]
[1:58:40][Run an -O2 build without asserting][:lighting :run]
[1:59:06][The light looks better, but with shiny :sampling errors][:lighting :run]
[1:59:47][Quadruple the LIGHT_LOOKUP_VOXEL_DIM_X and LIGHT_LOOKUP_VOXEL_DIM_Y and make UpdateLighting() quarter the VoxCellDim in X and Y][:lighting]
[2:00:16][Hit an OpenGL error][:lighting :run]
[2:00:26][Revert LIGHT_LOOKUP_VOXEL_DIM_X, LIGHT_LOOKUP_VOXEL_DIM_Y and VoxCellDim to their original values][:lighting]
[2:00:41][Consider bigger light sources to be our only option][:lighting :run]
[2:01:32][@frizi09][Bigger and slightly weaker light source could work there, though][:lighting]
[2:01:51][Our light is pretty good][:lighting :run]
[2:02:08][Make AddPlayer() increase the lights' size to 0.7 and decrease the brightness to 0.1][:lighting :"procedural generation"]
[2:02:48][Our moving lights are less square][:lighting :run]
[2:03:14][Uncomment the Mestre() calls in SumLight()][:lighting]
[2:03:37][Our moving lights are more radial][:lighting :run]
[2:03:52][Make AddPlayer() increase the lights' size to 1][:lighting :"procedural generation"]
[2:04:17][@pfizzyenator][How trivial is it to move to GPU?][:lighting]
[2:04:44][This bigger light actually looks square as the main light source outdoors][:lighting :run]
[2:07:00][Make AddPlayer() increase the lights' brightness to 0.5][:lighting :"procedural generation"]
[2:07:30][Our lights are blown out][:lighting :run]
[2:07:42][Reinstate the SurfaceReflect light floor removal of 0.01][:lighting]
[2:08:27][Our light fall-off is radial][:lighting :run]
[2:10:27][Rewrite the SurfaceReflect floor removal and ACESFilm() application][:lighting]
[2:10:54][Our light fall-off is radial][:lighting :run]
[2:11:03][Make StandardLightingPattern() increase the room lights' brightness to 0.5][:lighting :"procedural generation"]
[2:12:12][Patches of the solution fall to full darkness][:lighting :run]
[2:13:15][Make StandardLightingPattern() increase the room lights' brightness to 1][:lighting :"procedural generation"]
[2:13:32][Patches of the solution still fall to full darkness][:lighting :run]
[2:14:20][Revert the room lights' brightness to 0.05 in StandardLightingPattern(), and that of the head and glove lights to 0.1 in AddPlayer()][:lighting :"procedural generation"]
[2:15:03][Our light is dim but circular][:lighting :run]
[2:15:06][Decrease the SurfaceReflect light floor removal from 1 to 0][:lighting]
[2:15:19][Our light fall-off is square][:lighting :run]
[2:15:37][Try squaring the SurfaceReflect][:lighting]
[2:15:59][Our light fall-off is way less blocky][:lighting :run]
[2:16:19][Increase the SurfaceReflect multiplier from 100 to 1000][:lighting]
[2:16:24][Our light brightens a touch][:lighting :run]
[2:17:06][Partially revert the SurfaceReflect light floor removal to 0][:lighting]
[2:17:13][Our light fall-off is square][:lighting :run]
[2:17:38][Try to flatten the ACES filmic tone mapping curve[ref
site="Krzysztof Narkowicz"
page="ACES Filmic Tone Mapping Curve"
url=https://knarkowicz.wordpress.com/2016/01/06/aces-filmic-tone-mapping-curve/][ref
site=Desmos
page="Graphic Calculator"
url=https://www.desmos.com/calculator]][:lighting :research]
[2:19:31][Try setting B to 0 in ACESFilm()][:lighting]
[2:19:44][Our light fall-off doesn't differ much][:lighting :run]
[2:20:05][Play with the ACES filmic tone mapping curve[ref
site=Desmos
page="Graphic Calculator"
url=https://www.desmos.com/calculator]][:lighting :research]
[2:21:02][Try setting Z to 0.05 \[typo\] in ACESFilm()][:lighting]
[2:21:10][Our light fall-off remains square][:lighting :run]
[2:21:44][Revert ACESFilm()][:lighting]
[2:21:56][@pfizzyenator][I think you typed 0.05?][:lighting]
[2:22:04][Fix typo of Z from 0.05 to 0.5 in ACESFilm()][:lighting]
[2:22:06][Our light fall-off remains square][:lighting :run]
[2:23:22][Revert ACESFilm()][:lighting]
[2:24:02][Consider adding self-illumination and bloom, maybe leaving the square fall-off, removing 3D from the collision and adding gameplay rooms][:lighting :run]
[2:26:56][Enable LIGHTS_ARE_SPHERES][:lighting]
[2:27:22][Our light fall-off isn't materially different][:lighting :run]
[2:27:35][Disable LIGHTS_ARE_SPHERES][:lighting]
[2:27:41][Our light fall-off isn't materially different][:lighting :run]
[2:27:52][Decrease RayCount from 16 to 8 in GridRayCast()][:lighting :"procedural generation"]
[2:27:56][The light looks great][:lighting :run]
[2:28:51][Call it a day, with the determination to add bloom next time][:speech]
[2:29:10][@pfizzyenator][Framerate too high! Go back to 1 fps!]
[2:29:20][Thank you, everyone][:speech]
[2:30:21][@frizi09][We need an RTX ON comparison][:lighting]
[2:30:24][Thanks, everyone][:speech]
[/video]

View File

@ -0,0 +1,125 @@
[video output=day654 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Self-illuminating Floor Tiles" vod_platform=youtube id=w4lHAdy6KaA annotator=Miblo]
[0:00][Recap and set the stage for the day][:speech]
[0:18][Demo the :lighting][:run]
[2:10][Determine to add self-illuminating tiles][:lighting :run]
[4:11][Reacquaint ourselves with our :rendering pipeline][:research]
[11:14][Consider doing self-illumination through the ACES film curve vs directly (like the cutscene)][:lighting :research]
[14:50][Reacquaint ourselves with the source of FragEmission][:lighting :research]
[15:57][Introduce the notion of FragTone in the vertex and fragment shaders in CompileZBiasProgram()][:lighting]
[17:02][:Run successfully][:lighting]
[17:16][Indent the fragment shader]
[18:08][Yearn for lunch][:speech]
[18:58][Indent the fragment shader (cont.)]
[21:39][@dedknd][Not sure if this is part of Buddhist teaching]
[22:23][@ryanfleury][Don't tell me this is about the ~4coder layer]
[23:13][Reacquaint ourselves with the fog, emission, etc. "tuning knobs" in the fragment shader][:rendering :research]
[25:43][Separate out the fogging and ACES filtered :rendering knobs]
[28:22][The game is not tone-mapped, and the cutscene looks right][:rendering :run]
[28:53][Premiere the cutscene narration][:run]
[32:09][The cutscene is still working][:rendering :run]
[32:32][@chillagen][No way, this game has TF2 hats?]
[32:58][Thank you for the sub gifting][:speech]
[33:56][@redunlocked][Your posh British accent isn't terrible]
[34:42][Start to enable PushQuad() to set the Tone renaming Reserved to Tone in textured_quad][:"data structure" :rendering]
[37:54][@ryanfleury][A really sweet ~4coder layer feature would be to log per-line edits and correlate them with timestamps in a session]
[38:08][Plug @AndrewJDR's annotated [~hero Handmade Hero] source code linking to the indexed episode guide[ref
site=GitHub
page="HandmadeHero / annotated_cpp"
url=https://github.com/HandmadeHero/annotated_cpp]]
[39:08][Enable PushQuad() to set Tone to a VertTone, which is either 255 or, if lighting is off, 0][:lighting :rendering]
[41:29][The game remains not tone-mapped][:rendering :run]
[41:40][Specify a Tone vertex array in UseProgramEnd() and UseProgramBegin()][:rendering]
[44:27][@botondar][As far as I know, on modern GPUs the input assembler is just shader code, so you can just fetch them manually (if I understood you correctly)][:rendering]
[45:27][@brian_nevec][You can in D3D11 with StructuredBuffer][:rendering]
[45:46][Associate VertTone in OpenGLCreateProgram()][:rendering]
[46:18][@brian_nevec][Yeah, you can use the vertexid to index the buffer][:rendering]
[47:00][Our tone-mapping is back, the debug overlay is now correctly unlit and the cutscene still looks right][:lighting :rendering :run]
[47:35][Determine to add self-illuminating blocks][:lighting :speech]
[48:23][We've have it all][:speech]
[49:32][@ryanfleury][This DLSR autofocus is in... UNACCEPTABLE CONDITION]
[50:28][Change CreateWorld() to connect the dungeon entrance room to the north of (rather than below) the forest entrance][:"procedural generation"]
[51:24][Traverse to the outdoors, where the ground cover is not lit][:lighting :run]
[52:13][Reacquaint ourselves with the ground cover drawing code][:rendering]
[52:58][Make VertexOut() set the Tone to 255 (i.e. tone-map and light it)][:rendering]
[53:05][Our ground cover is lit again][:lighting :run]
[53:14][@ponkkiz][It fixed the blocky :lighting bug?]
[53:24][Traverse to the dungeon][:run]
[54:22][Volunteer voice acting services to "Downward Dungeon"][:speech]
[56:52][Sample reel for "Downward Dungeon"][:speech]
[57:14][Workshop some dungeon-based game titles][:speech]
[58:50][@wakeuphate][There should be a game about travelling to the dungeon but not actually doing the dungeon]
[59:43][Workshop some dungeon-based game titles (cont.)][:speech]
[1:00:17][@vtlmks]["Dude, Where's the Dungeon?"]
[1:00:34][@technicbeam][I wrote a game once called "Walking Simulator" - it was a text adventure where all you did was walk different directions and 'look']
[1:00:43][Pitch "Dungeon?" / "Imagine Dragons"][:speech]
[1:03:09][@kindly_sloth][You could make a Tycoon-style game where you design such a town]
[1:04:37][@sneakybob_wot]["Dave Made a Dungeon"]
[1:05:01][Toggle on TileSwitchPattern in CreateDungeon()][:"procedural generation"]
[1:06:08][@spacenaming]["My First Dungeon", and make the game all bright red, yellow and blue]
[1:06:14][Traverse to the dungeon's tile switches][:run]
[1:07:10][Reacquaint ourselves with the tile switch :lighting code][:research]
[1:07:59][Make ExecuteBrainSwitches() decrease the light's brightness from 10 to 1][:lighting]
[1:08:17][Consider making :"hot reloading" work with the :"procedural generation"][:research]
[1:08:48][Make CreateWorld() place the player in the dungeon][:"procedural generation"]
[1:09:10][Start in the dungeon and toggle the tile switches][:run]
[1:09:42][Consider not adding a light source, but just setting the emission of the cube][:lighting :research]
[1:10:28][@e11m][Is the light never going away?][:lighting]
[1:10:34][Consider removing the AddPieceLight() call from TileSwitchPattern()][:lighting :"procedural generation" :research]
[1:10:57][Imagine the "Downward Dungeon" theme song][:speech]
[1:11:58][Prevent TileSwitchPattern from calling AddPieceLight()][:lighting :"procedural generation"]
[1:12:19][The tiles turn on but do not light up][:lighting :"procedural generation" :run]
[1:12:31][Prevent AddPlayer() from adding a head light, and make the glove's light less green][:lighting :"procedural generation"]
[1:13:17][The glove light is a bit too bright][:lighting :"procedural generation" :run]
[1:13:21][Make AddPlayer() dim the (commented out) head light from 0.1 to 0.05][:lighting :"procedural generation"]
[1:13:29][The glove light remains too bright][:lighting :"procedural generation" :run]
[1:13:35][Make AddPlayer() dim the glove light from 0.1 to 0.025][:lighting :"procedural generation"]
[1:13:43][Our glove's glow is more like it][:lighting :"procedural generation" :run]
[1:13:57][Make TileSwitchPattern() apply the Tag_Stone tag][:lighting :"procedural generation"]
[1:15:51][Our stone switches look better][:lighting :"procedural generation" :run]
[1:16:18][@aukkras][Heh, the certificate for ~4coder website[ref
site=4coder
url=https://4coder.net/] expired]
[1:16:52][The :AI goes wherever it wants][:run]
[1:17:10][@kindly_sloth][Did one of those heads just phase through the wall?]
[1:19:09][@dedknd][03/04/22 Allen: I am not currently developing ~4coder. But I intend to pick it up again soon to get the codebase organized for open sourcing]
[1:19:34][Consider how to represent self-illumination][:"entity system" :research]
[1:21:33][Try making UpdateAndRenderEntities() pass 1 as the Emission value to PushCube()][:"entity system" :lighting]
[1:21:40][All our cubes are lit][:"entity system" :lighting :run]
[1:21:44][Revert UpdateAndRenderEntities() to pass 0 as the Emission value to PushCube()][:"entity system" :lighting]
[1:22:15][Consider how best to articulate our desired Emission value to the system][:"entity system" :lighting :research]
[1:24:01][Introduce cube_piece containing an Emission value to replace cube_uv_layout in entity_visible_piece][:"data structure" :"entity system" :lighting]
[1:25:26][The game still runs][:run]
[1:25:30][Make UpdateAndRenderEntities() unpack the Emission[ref
author="Frank Zappa"
title="Dumb All Over"
publisher=YouTube
url=https://www.youtube.com/watch?v=Y8TKiRo-W4U]][:"entity system" :lighting]
[1:26:46][There are no emission cubes][:"entity system" :lighting :run]
[1:26:58][Make ExecuteBrainSwitches() set the switch's emission to 50][:"entity system" :lighting]
[1:27:24][The switches don't emit light][:"entity system" :lighting :run]
[1:27:54][Make UpdateAndRenderEntities() pass the unpacked Emission to PushCube()][:"entity system" :lighting]
[1:28:19][The switches emit light, but don't tell the :lighting system they're doing it][:"entity system" :lighting :run]
[1:28:54][Reacquaint ourselves with PushOccluder() and its use][:"entity system" :lighting :research]
[1:36:00][Replace the IsLight boolean with an Emission float in lighting_box][:"data structure" :"entity system" :lighting]
[1:38:21][The switches still emit light][:"entity system" :lighting :run]
[1:38:44][Fold PushLight() and PushOccluder() into a unified PushLightingElement()][:"entity system" :lighting]
[1:41:24][The switches still emit light][:"entity system" :lighting :run]
[1:41:39][Make ExecuteBrainSwitches() set the Emission on the switch's occluder, rather than the base piece][:"entity system" :lighting]
[1:41:56][The switches are not lit][:"entity system" :lighting :run]
[1:42:13][Make ExecuteBrainSwitches() also set the Emission on the switch's base piece][:"entity system" :lighting]
[1:43:01][@sagian2005][What would translucent :lighting even be?]
[1:43:15][The switches remain not telling the :lighting system about their emission][:"entity system" :run]
[1:44:06][The light leaks a little][:lighting :run]
[1:45:10][Make UpdateAndRenderEntities() unpack and pass the Emission of occluders to PushLightingElement()][:"entity system" :lighting]
[1:45:50][The switches emit light and tell the :lighting system about it][:"entity system" :run]
[1:46:06][Make ExecuteBrainSwitches() set the Color of the switch's occluder piece][:"entity system" :lighting]
[1:46:29][The switches emit cyan light][:"entity system" :lighting :run]
[1:47:15][Make ExecuteBrainSwitches() dim the light from 50 to 25][:"entity system" :lighting]
[1:47:25][Our tile switch light is better][:"entity system" :lighting :run]
[1:47:52][That's it, with a plug of Molly Movie Club[ref
site="Molly Movie Club"
url=https://www.mollymovieclub.com/]][:speech]
[1:49:35][@me_love_pomegranate][Are you watching Better Call Saul season 6?]
[1:50:52][@rooctag][Do I need to watch Interstellar to enjoy the podcast?]
[1:57:20][Thanks, everyone][:speech]
[/video]

View File

@ -0,0 +1,123 @@
[video output=day655 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Revisiting Entity Movement" vod_platform=youtube id=pITjYkjGha4 annotator=Miblo]
[0:01][Recap and set the stage for the day][:speech]
[0:44][Plug "Twenty Minutes of Reasons to Use the ~RemedyBG Debugger"[ref
title="Twenty Minutes of Reasons to Use the RemedyBG Debugger"
author="Molly Rocket"
publisher=YouTube
url=https://www.youtube.com/watch?v=r9eQth4Q5jg]][:research]
[1:38][Demo our future desire for a bloom filter and participating media (dust), with a few words on other film artifacts such as halation][:filtering :lighting :run]
[9:18][Determine to build some basic entity interactions][:movement :run]
[14:59][Consider fixing the glove's :movement to discrete patterns][:run]
[23:12][Determine to switch to an entirely transactional :collision system][:research]
[23:31][Thoughts on freedom, constraints and making problems tractable][:research]
[26:13][Real-time transactional :movement and :collision][:research]
[28:31][Demo our need for leading-edge, sustaining action and trailing-edge (attack, sustain and release) events][:movement :run]
[31:26][Remove the voxel-based :collision code, and the floating movement mode][:movement]
[32:36][Previously floating entities (glove and familiar) no longer move][:movement :run]
[33:18][Fully remove MovementMode_Floating][:movement]
[34:11][Consider removing entity_movement_mode entirely][:movement :research]
[35:04][Re-add MovementMode_Floating and remove MovementMode_AngleOffset and MovementMode_AngleAttackSwipe][:movement]
[35:30][Consider removing entity_movement_mode entirely (cont.)][:movement :research]
[38:10][Rename entity_movement_mode to entity_animation][:animation :"entity system"]
[40:58][Plan to separate out transactional :movement from :animation][:research]
[42:21][Introduce UpdateAnimation() to adopt code from UpdateAndRenderEntities()][:animation]
[44:18][@wassimulator][Could you, please, at some point explain what "internal", "external", "function" and "static" before functions do? I vaguely understand what they do but not concretely][:language]
[44:57][Understanding "static"][:language]
[45:25][Understanding "static" for function-local variable persistence][:language]
[47:31][Understanding "static" for global variables and functions][:language]
[50:41][@mmozeiko][In C++11 and up there is no problem with multiple thread and local static variable initialization][:language]
[51:01][@mmozeiko][It guarantees that initialization is thread-safe. Puts lock around it][:language]
[51:17][@mmozeiko][Sure. But it works][:language]
[52:29][@zufaelligertyp][I always imagined local static variables as being the same as global static lifetime-wise. Only difference that the variable is only available in this function / scope. Isn't this how it works in C?][:language]
[54:36][@mmozeiko][If you don't initialize variables with code (like result of function call) then pretty much all compilers will simply put constant value you initialized in global data segment, and there will be no code run on "first time"]
[55:03][Make UpdateAnimation() take a sim_region * and particle_cache *][:animation]
[58:26][Non-floating entities continue to move and animate][:animation :movement :run]
[59:37][@kwmar][Local static variables actually use a thread-local flag they examine if they've been already initialized. If not, then slow part comes. But in VS there is one such guard per local static variable, so if you have 10 of them in a function then you pay 10 times the guard check per function][:language]
[1:00:25][Add an Animation_Floating case to UpdateAnimation()][:animation]
[1:01:41][Floating entities don't move][:animation :movement :run]
[1:02:03][Consider working on Type_brain_familiar][:"entity system" :research]
[1:04:05][@mindmark42][You can still swap your head with ground tiles or at least the buttons, I think][:"entity system"]
[1:04:41][Possess a switch and various entities][:"entity system" :run]
[1:07:15][@philbohun][Does [@cmuratori Casey] have enough subs for a React stream? That would be the comedy of the century]
[1:07:43][Reacquaint ourselves with the entity possession code in ExecuteBrainHero()][:"entity system" :research]
[1:09:12][Toggle off the brained entity swapping code in ExecuteBrainHero()][:"entity system"]
[1:09:27][Entity possession no longer happens][:"entity system" :run]
[1:09:38][Plan pattern-based :movement and glove striking rules, with interruptibility][:research]
[1:15:59][@tinspin][Hi, does anyone in chat know if you can make a Win .exe that runs fine on both 7 & 10 without using compatibility mode?]
[1:16:55][Determine to introduce move queues][:"entity system" :movement :research]
[1:22:20][Introduce move_queue_entry for the entity struct to contain][:"data structure" :"entity system" :movement]
[1:26:17][Is [@j_blow Jon] still streaming Counter-Strike?][:speech]
[1:26:27][@wassimulator][No]
[1:26:30][@nextra24][It's over]
[1:27:18][@nextra24][Multiple days of playoffs, final best-of-three today]
[1:27:46][@nextra24][No, that best-of-three determined the overall winner]
[1:28:07][@wassimulator][Faze won or phase one?]
[1:28:14][Remove move_spec and DefaultMoveSpec()][:"data structure" :movement]
[1:29:19][Plan the glove's tile occupation][:movement :run]
[1:32:07][Remove ddP from entity][:"data structure" :"entity system" :movement]
[1:32:48][Start to make ExecuteBrainHero() move the glove towards its parent entity when at rest][:"entity system" :movement]
[1:35:38][The game runs][:run]
[1:35:40][Plan move queue execution, and glove positioning relative to the player][:movement :research]
[1:38:44][@internationalizationist][Q: Do we have sound effects at the moment?][:audio]
[1:39:31][Hear no sound][:audio :run]
[1:39:36][Reacquaint ourselves with PlaySound() and OutputPlayingSounds()][:audio :research]
[1:41:58][Step through PlaySound(), to find that our sound is not found][:"asset system" :audio :run]
[1:42:59][Investigate why our sounds are not found][:"asset system" :audio :research]
[1:44:24][Break on GetBestMatchSoundFrom()][:"asset system" :audio :run]
[1:46:09][Reacquaint ourselves with ProcessAudioImport() and UpdateAssetDataFromFile()][:"asset system" :audio :research]
[1:50:32][Reacquaint ourselves with AddAssetToHash()][:"asset system" :audio :research]
[1:51:38][@nomad_pixel][Is that a mechanical keyboard? What switches are those?]
[1:53:09][@klblaz][Have you tried keyboards with MX Brown? They are basically the same switch]
[1:53:55][@dandymcgee][What's the difference? They're meant to have the same actuation profile, no?]
[1:54:52][@mdciotti][Zealio Purple switches supposedly have a very similar force curve to the Razer Orange switches. You'd have to build the keyboard yourself, though]
[1:56:49][Reacquaint ourselves with AddAssetToHash() (cont.)][:"asset system" :audio :research]
[1:57:38][Add StopCodeHere lines in AddAssetToHash() if TypeID == Asset_Audio and if Tags\[0\] == Tag_Bloop][:"asset system" :audio]
[1:58:42][Break on StopCodeHere in AddAssetToHash() to find that Tags\[\0\] is Tag_ChannelIndex, not Tag_Bloop][:"asset system" :audio :run]
[1:59:54][Add a MatchElement_Channel to asset_match_vector_element for AddAssetToHash() to use][:"asset system" :audio]
[2:01:53][Hit a read access violation on Tag->ID in AddAssetToHash()][:"asset system" :audio :run]
[2:03:19][Remove MatchElement_Channel from asset_match_vector_element and make AddAssetToHash() store the Tag_ChannelIndex in MatchElement_FacingDirection][:"asset system" :audio]
[2:03:35][Hit a read access violation on Tag->ID in AddAssetToHash()][:"asset system" :audio :run]
[2:03:43][Remove Tag_ChannelIndex case from AddAssetToHash()][:"asset system" :audio]
[2:03:52][Hit a read access violation on Tag->ID in AddAssetToHash()][:"asset system" :audio :run]
[2:03:57][Undo our changes to AddAssetToHash() and asset_match_vector_element][:"asset system" :audio]
[2:04:31][Hit a read access violation on Tag->ID in AddAssetToHash()][:"asset system" :audio :run]
[2:05:07][Step through AddAssetToHash() inspecting the Asset->HHA][:"asset system" :audio :run]
[2:07:28][Check the chat][:speech]
[2:08:22][Thoughts on open-source software as worker exploitation][:speech]
[2:11:33][Investigate our Tag->ID read access violation][:"asset system" :audio :run]
[2:15:01][@nomad_pixel][Can you put a data breakpoint if it's always index 173 or whatever on when something writes to it?][:"asset system" :audio]
[2:15:19][Investigate our Tag->ID read access violation (cont.)][:"asset system" :audio :run]
[2:24:56][Delete base_game.hha and :run the game to rebuild it][:"asset system" :audio]
[2:26:26][:Run the game successfully with the new base_game.hha][:"asset system" :audio]
[2:26:47][Add a MatchElement_Channel to asset_match_vector_element for AddAssetToHash() to use][:"asset system" :audio]
[2:27:43][:Run successfully, with bloops][:"asset system" :audio]
[2:28:18][Toggle off the attack bloops in ExecuteBrainHero()][:"asset system" :audio]
[2:29:31][Toggle on the intro cutscene music in GameUpdateAndRender(), updating to the current :"asset system" code][:audio]
[2:32:58][Our music plays, but tears][:audio :run]
[2:33:36][Note the need to thread the :audio][:research :threading]
[2:36:05][Our music continues to tear][:audio :run]
[2:36:59][Call it there][:speech]
[2:37:26][@teamrandb][Q: If one wanted to spawn a second window, how would one go about tackling it? To give context, let's say one wanted to move most of [~hero Handmade Hero]'s debug menu to a separate window, where the main DebugUI would be on Window 2 while the game is on Window 1. (Like to show the graphs on a separate window.) I'm struggling to figure out how much of the message handling, and the game logic needs to be separated, or if it could "as simple as" two separate buffers, and a WindowID for when we push tasks]
[2:39:03][Call that a day][:speech]
[2:39:23][@bob_from_hearthstone][Is the problem with exploitation of the working class really an open source problem? You still can have a commercial licensing on an open source codebase, right? The problems seem to be more related to the free software where the work put on a software can be taken and monetized without proper rewarding of the workers. (Sorry for bringing the topic back)]
[2:48:17][@gregg_ink][Open source programmers made a choice to give the software for free. That's not exploiting people]
[2:50:00][@khbatus][But open source is good for regular people. Is there something like open source but not free for big corporations?]
[2:50:20][@distractedmosfet][Yeah AGPL, it's actually been around a while but the corps in the space, like Google, hate it and push against it]
[2:51:56][@gregg_ink][By that logic, did [@cmuratori Casey] choose to be exploited by creating [~hero Handmade Hero]?]
[2:54:21][@arkandos_][Q: If I learn something from reading the [~hero Handmade Hero] source, can I use those same techniques in other closed-source projects?]
[2:55:19][@gheoan][@handmade_hero Are you using any open source code in your proprietary code?]
[2:55:36][@kwmar][What about [@nothings Sean]'s toolbox?[ref
site=GitHub
page="nothings / stb"
url=https://github.com/nothings/stb]][:library]
[2:55:52][@amirh12][Don't you use OpenGL?][:library]
[2:56:11][@gregg_ink][Were you not using stb[ref
site=GitHub
page="nothings / stb"
url=https://github.com/nothings/stb] for fonts?][:library]
[2:56:32][@distractedmosfet][OpenGL is an open spec, not open software][:library]
[2:56:59][@slava_radko][@handmade_hero So basically it's fine if I learn from your stream, then close the stream and implement something like you, for example DLL loading and architecture, but implemented myself?]
[2:58:31][@wassimulator][Q: My renderer in AV-Racer uses OpenGL. Are there any practical drawbacks to it? Would you say I should switch to D3D on my next project or something else?][:library]
[2:59:06][@bewwyss][How to calculate how much should go to an open source project if I make profits, in percent, let's say?]
[3:00:05][That's that][:speech]
[/video]

View File

@ -0,0 +1,66 @@
[video output=day656 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Sketching Out Move Queues" vod_platform=youtube id=-GBFPHJbXFQ annotator=Miblo]
[0:00][Recap and set the stage for the day][:speech]
[0:44][The :audio tears and previously floating entities no longer move][:movement :run]
[2:06][@thesandvichmaker][This poor tortured piano][:audio]
[2:27][Toggle off the OutputPlayingSounds() call in GameGetSoundSamples()][:audio]
[3:48][The music has gone][:audio]
[3:56][Use #if 0 TEMPORARY][:language]
[5:17][Hero hopping feels fine, just needing trailing-edge events][:movement :run]
[6:38][Determine to move the glove with the hero, and sweep out a prescribed pattern upon attack][:movement :run]
[9:47][Continue with the idea of a move queue][:"entity system" :movement :research]
[10:51][Augment move_queue_entry with Damage and Speed][:"data structure" :"entity system" :movement]
[13:10][Determine to implement non-recallable glove attacks][:"entity system" :movement :research]
[17:37][Consider after-touch, and chaining attacks][:"entity system" :movement :research]
[18:26][Embark on attack patterns in ExecuteBrainHero(), changing Dest to Delta in move_queue_entry][:"data structure" :"entity system" :movement]
[20:20][Thoughts on the game looking grid-based, but actually being arbitrary][:geometry :research]
[21:10][Enable ExecuteBrainHero() to begin attacks in the correct direction][:"entity system" :movement]
[28:39][Set up ExecuteBrainHero() to push attack patterns onto the move queue][:"entity system" :movement]
[29:54][@notepaduser][enum is not in C][:language]
[31:34][Enable ExecuteBrainHero() to push attack patterns onto the move queue (cont.)][:"entity system" :movement]
[32:40][Consider chaining attacks together][:"entity system" :movement :research]
[33:57][Augment entity with a MoveGroupCount to limit the attack chain length created by ExecuteBrainHero()][:"data structure" :"entity system" :movement]
[36:28][Consider what constitutes the glove having "returned to hero"][:"entity system" :movement :research]
[38:19][Consider item statistics][:"entity system" :research]
[41:35][@notepaduser][Guys, if integers are more efficient than floats, should we make our int pointers point to decimal numbers?]
[42:05][Consider item statistics (cont.)][:"entity system" :research]
[43:26][Introduce stats][:"data structure" :"entity system"]
[44:53][Consider how to articulate modifiable glove statistics][:"entity system" :run]
[48:04][@frizi09][The glove has six slots for colorful stones, and if you fill them all, you can snap your fingers and half of the world dissolves]
[48:45][Introduce move_square_type and stat_coeff for stats to use / contain][:"data structure" :"entity system"]
[52:05][Introduce move_pattern][:"data structure" :"entity system"]
[53:09][Consider status effects][:"entity system" :research]
[56:42][Fill in move_pattern, introducing move_pattern_entry and move_queue_flag][:"data structure" :"entity system"]
[1:00:26][@tk_dev][@handmade_hero Not to be disrespectful, but it seems you are not following your own advice right now. I would suggest you implement the moving in a corner and continue from there. Sorry]
[1:00:34][Reflect on our stats and move_pattern sketch][:"entity system" :research]
[1:01:48][Add a MoveFlag_Ephemeral to move_queue_flag][:"entity system"]
[1:02:30][Reflect on our stats and move_pattern sketch (cont.)][:"entity system" :research]
[1:04:19][Enable ExecuteBrainHero() to initialise attack patterns, augmenting move_pattern with an EntryCount][:"data structure" :"entity system"]
[1:06:28][@rationalcoder][@tk_dev I had a similar thought, but you need some initial bullshit idea of structs and enums to start playing with usage code]
[1:06:59][@sagian2005][I don't understand how the "pattern" is involved in the game play. Like, what is the function of a pattern?][:"entity system"]
[1:08:33][@pileopoop][Like a chess move]
[1:09:19][Enable ExecuteBrainHero() to translate attack patterns from their canonical orientation, to the requested one][:"entity system"]
[1:13:14][Set up ExecuteBrainHero() to handle move queue overflow][:"entity system"]
[1:14:02][Explore ~4coder's function prototype HUD][:admin]
[1:15:59][Set up ExecuteBrainHero() to handle move queue overflow (cont.)][:"entity system"]
[1:17:29][Set up ExecuteBrainHero() to limit move queue pushes to the MaxMoveGroupCount][:"entity system"]
[1:18:35][Consider how / when to evaluate entity stats][:"entity system" :research]
[1:19:53][@sagian2005][Should the "if" just be the assert?]
[1:20:16][Consider how / when to evaluate entity stats (cont.)][:"entity system" :research]
[1:23:15][Reacquaint ourselves with the game update loop in Simulate()][:research]
[1:24:33][Consider how / when to evaluate entity stats (cont.)][:"entity system" :research]
[1:27:20][Consider entity stats evaluation to be harder than the move queue][:"entity system" :research]
[1:28:07][Use swappable hats to guide our entity stats evaluation considerations][:"entity system" :research]
[1:34:00][Consider evaluating entity stats when adding to hash][:"entity system" :research]
[1:35:29][Try making AddEntityToHash() recompute stats][:"entity system"]
[1:37:30][Augment entity with BaseStats, ActiveStats and AccumStats][:"data structure" :"entity system"]
[1:38:17][@thebaker__][Have you considered just dynamically calculating stats based off the current modifiers?][:"entity system"]
[1:40:35][@thebaker__][Well that way they just never get stale][:"entity system"]
[1:43:49][Reacquaint ourselves with our ATan2() calls][:mathematics :research]
[1:44:56][Rename the entity struct's ActiveStats and AccumStats to Stats and StatsAccum][:"data structure" :"entity system"]
[1:46:56][Introduce AdvanceEntityStats() for AddEntityToHash() to call][:"entity system"]
[1:48:04][Augment stats with Speed, for ExecuteBrainHero() to use][:"data structure" :"entity system"]
[1:49:25][Finish making ExecuteBrainHero() push moves onto the queue][:"entity system"]
[1:51:21][Make ExecuteBrainHero() consider the glove to be with the body if it is closer than 0.5 units away][:"entity system"]
[1:52:55][TODO([@cmuratori casey]): Set a return move when there's no moves in the queue?][:"entity system"]
[1:53:30][That's it for today][:speech]
[/video]

View File

@ -0,0 +1,99 @@
[video output=day657 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Implementing Move Queues" vod_platform=youtube id=Ax5vU4mXJ48 annotator=Miblo]
[0:01][Recap and set the stage for the day moving the glove][:"entity system" :run]
[0:34][Describe our sketched out move patterns and queues, and stats][:"data structure" :"entity system" :research]
[5:25][Walk through our move queue enqueuing code in ExecuteBrainHero()][:"entity system" :research]
[7:38][Demo the brain-directed movement synchronisation][:"entity system" :run]
[8:59][Consider move queue-directed movement integrity][:"entity system" :run]
[11:41][Our facing direction is wrong when pressing Up][:"entity system" :run]
[11:57][Investigate why our facing direction is wrong][:"entity system" :research]
[12:30][Make ExecuteBrainHero() compute the FacingDirection with the ATan2 of the X vector][:"entity system"]
[12:51][Our facing direction remains wrong][:"entity system" :run]
[13:05][Investigate why our facing direction is wrong][:"entity system" :research]
[13:42][Make ExecuteBrainHero() compute the FacingDirection with the ATan2 of y / x of the X vector][:"entity system"]
[13:54][Our facing direction is now correct][:"entity system" :run]
[14:07][Consider where the glove should sit][:"entity system" :run]
[16:43][Determine to put the glove on the hero's tile, and not occupy tiles it passes through][:"entity system" :research]
[24:52][Make ExecuteBrainHero() move the glove without transactionally occupying tiles][:"entity system"]
[26:29][Our glove doesn't move with us][:"entity system" :run]
[26:55][Investigate why the glove doesn't move][:"entity system" :research]
[28:00][Move without hitting extra keys, and the glove still not following us][:"entity system" :run]
[28:11][Break into the "glove at rest" branch in ExecuteBrainHero()][:"entity system" :run]
[29:58][Step through UpdateAnimation()][:animation :"entity system" :run]
[33:03][Reacquaint ourselves with UpdateAnimation()][:animation :"entity system" :research]
[34:23][Check that the glove's :animation data doesn't get overwritten][:"entity system" :research]
[36:46][Break into AddPlayer() for the glove's entity ID (10845), then see what UpdateAnimation() does to that entity][:animation :"entity system" :run]
[44:38][Find that UpdateAndRenderEntities() sets Entity->GroundP][:"entity system" :research]
[47:23][Remove GroundP from entity][:"data structure" :"entity system"]
[49:28][Entities are now in different locations][:"entity system" :run]
[49:54][Our glove follows us, but does not animate][:animation :"entity system" :run]
[51:03][Investigate why the glove does not animate][:animation :"entity system" :research]
[52:50][Fix ExecuteBrainHero() to set the Glove's tMovement to 0][:animation :"entity system"]
[53:10][Our glove follows us, animating smoothly][:animation :"entity system" :run]
[53:46][Determine to offset the glove's location relative to the player][:"entity system" :research]
[54:40][Try making AddPlayer() offset the glove in X][:"entity system"]
[55:13][Our glove is offset in X][:"entity system" :run]
[55:26][Try making AddPlayer() offset the glove in Z][:"entity system"]
[55:56][Our glove is offset in Z][:"entity system" :run]
[56:10][Increase the glove's X offset from 0.25 to 0.5 in AddPlayer()][:"entity system"]
[56:18][Our glove offsetting doesn't respect its parent entity's facing direction][:"entity system" :run]
[59:47][Traverse the dungeon admiring the :lighting][:run]
[1:01:28][@mallesbixie][With a fixed offset from the actual position, animating would get hard, I guess][:animation :"entity system"]
[1:02:19][Determine to dequeue moves off the move queue][:"entity system" :research]
[1:03:42][Enable UpdateAndRenderEntities() to dequeue moves off the move queue, augmenting entity with a MoveQueueIndex][:"data structure" :"entity system"]
[1:08:31][The game still runs][:run]
[1:08:43][Make UpdateAndRenderEntities() draw move queues][:"debug visualisation" :"entity system"]
[1:10:52][See no move queue drawings][:"debug visualisation" :"entity system" :run]
[1:11:02][Make UpdateAndRenderEntities() elevate the move queue drawing above the ground][:"debug visualisation" :"entity system"]
[1:11:28][Still see no move queue drawings][:"debug visualisation" :"entity system" :run]
[1:11:30][Make AddPlayer() set the Glove->Stats.MaxMoveGroupCount to 1, and ExecuteBrainHero() reset Glove->MoveQueueIndex to 0 when with the body][:"entity system"]
[1:13:41][Still see no move queue drawings][:"debug visualisation" :"entity system" :run]
[1:13:50][Scour ExecuteBrainHero() for bugs][:"entity system" :research]
[1:14:23][Break in to ExecuteBrainHero() to find the glove's stats are not set][:"entity system" :run]
[1:15:07][Change AddPlayer() to set the Glove->BaseStats.MaxMoveGroupCount to 1][:"entity system"]
[1:15:35][Break in to ExecuteBrainHero() to find the glove's stats remain not set][:"entity system" :run]
[1:15:51][accumulate entity stats]
[1:16:20][Love @insobot, and feel like @insofaras needs to use GPT-3 and have @insobot do everything][:speech]
[1:17:05][Make AdvanceEntityStats() acquire the Entity->BaseStats][:"entity system"]
[1:17:31][Break in to ExecuteBrainHero() to find the glove's stats are now set, and move queue boxes are drawn][:"debug visualisation" :"entity system" :run]
[1:18:11][Make ExecuteBrainHero() locate the move queue drawings relative to its entity's occupying position][:"debug visualisation" :"entity system"]
[1:19:35][Our move queue drawings work pretty well][:"debug visualisation" :"entity system" :run]
[1:19:44][Determine to make the glove return to the body after punching][:"entity system" :research]
[1:21:14][@technicbeam][People always wonder when @insobot is going to become sentient]
[1:21:48][Our move pattern rotates properly][:"entity system" :run]
[1:21:55][Investigate why the glove doesn't return to the body after punching][:"entity system" :research]
[1:22:18][Fix the glove reset condition in ExecuteBrainHero()][:"entity system"]
[1:22:34][Our glove now returns after punching][:"entity system" :run]
[1:22:55][Increase Glove->BaseStats.MaxMoveGroupCount from 1 to 2 in AddPlayer()][:"entity system"]
[1:23:11][We can chain punches, but the pattern direction is off][:"entity system" :run]
[1:23:30][Investigate why the second punch's direction is off][:"entity system" :research]
[1:25:03][@technicbeam][Have fun reading it, if you can find a copy. It's gotta be, what, 40 years old at least by now?]
[1:25:12][Gain insight into the chained punching direction][:"entity system" :run]
[1:25:32][Try using a WentDown input event in ExecuteBrainHero()][:"input handling"]
[1:26:16][@technicbeam][The Adolescence of P-1[ref
author="Thomas Joseph Ryan"
title="The Adolescence of P-1"
publisher="Macmillan Publishing"
isbn=0026065002]]
[1:26:29][We have HalfTransitionCount but not WentDown in game_button_state][:"data structure" :"input handling"]
[1:27:20][Make ExecuteBrainHero() also factor in the HalfTransitionCount to its attack checks][:"entity system" :"input handling"]
[1:27:55][We can chain punches in the correct directions][:"entity system" :run]
[1:29:15][Consider the definition of :collision][:"entity system" :research]
[1:30:31][Change ExecuteBrainHero() to give the glove a 1-step attack pattern][:"entity system"]
[1:30:53][Try our simple punch][:"entity system" :run]
[1:31:07][Introduce SetAnimation() for the ExecuteBrain*() functions to call, augmenting entity with a dtMovement][:animation :"data structure" :"entity system"]
[1:36:50][That all looks fine][:animation :"entity system" :run]
[1:37:04][Switch UpdateAndRenderEntities() to use the new Entity->dtMovement][:"entity system"]
[1:37:26][Our glove doesn't move][:animation :"entity system" :run]
[1:37:40][Consider where and how to set the glove's dtMovement][:"entity system" :research]
[1:40:58][Let UpdateAndRenderEntities() also move entities if their dtMovement is 0][:"entity system"]
[1:41:23][Our glove now moves][:animation :"entity system" :run]
[1:41:33][Increase the glove's animation speed from 4 to 8 in ExecuteBrainHero()][:animation :"entity system"]
[1:41:53][Our glove punches faster][:animation :"entity system" :run]
[1:42:44][@mallesbixie][Would the attack pattern define the speed?][:"entity system"]
[1:43:23][Make UpdateAndRenderEntities() set the Entity->dtMovement, and AddPlayer() the glove's BaseStats.Speed][:animation :"entity system"]
[1:45:13][Our glove still punches faster][:animation :"entity system" :run]
[1:45:16][Toggle to the 3-step attack pattern in ExecuteBrainHero()][:"entity system"]
[1:45:43][Try out our fast-slow-fast punch][:animation :"entity system" :run]
[1:46:24][@spacenaming][There is a function to determine if the button was pressed this frame (named WasPressed)][:"input handling"]
[1:46:29][Call it for today with a glimpse into the future doing damage and collapsing down to grid][:speech]
[/video]

View File

@ -0,0 +1,90 @@
[video output=day658 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Handling Glove Collisions" vod_platform=youtube id=GxMz9U7FJ0E annotator=Miblo]
[0:00][Recap and set the stage for the day doing glove :collision][:speech]
[0:11][Demo the glove's chaining move patterns][:"entity system" :run]
[1:23][Determine to handle glove :collision, on overlapping hit boxes][:"entity system" :run]
[6:07][Define a strike as Street Fighter-esque overlapping hit boxes][:collision :"entity system" :research]
[6:51][RayIntersectsBox() is for debug purposes][:collision :research]
[7:32][Prepare to handle glove :collision, considering switching to a grid][:"entity system" :research]
[9:52][Set up UpdateAndRenderEntities() to process projectile collisions in a post-pass loop][:collision :"entity system"]
[13:35][@richardycg][That entity_iterator would look lovely with the new C++ for-loop syntax][:language]
[13:57][@richardycg][lol, no, but it's the one thing they fixed][:language]
[15:26][@richardycg][for (entity *Projectile : IterateAllEntities(SimRegion)) { /**/ }]
[15:56][Add EntityFlag_Collider to entity_flags]
[16:29][@genughaben][By the way, what is your opinion of Rust?][:language]
[16:32][Set up UpdateAndRenderEntities() to work on EntityFlag_Collider in its post-pass :collision loop][:"entity system"]
[16:46][Further thoughts on modern languages][:language :rant :speech]
[17:26][Set up UpdateAndRenderEntities() to check if a projectile collides][:collision :"entity system"]
[18:32][Try out conversation box checking][:collision :"entity system" :run]
[19:05][Consider handling projectile :collision like conversation boxes][:"entity system" :research]
[20:00][@bryantdrewjones][Whats the obviously good for-loop syntax?][:language]
[22:39][@yuika_lamonting][Jai has: for array {action}][:language]
[23:15][Make UpdateAndRenderEntities() check if a projectile collides][:collision :"entity system"]
[24:09][Consider single-hit application schemes: invincibility frames, projectile disabling][:collision :"entity system" :research]
[28:37][Toggle to the 1-step attack pattern in ExecuteBrainHero()][:"entity system"]
[29:12][Try our simple punch][:"entity system" :run]
[29:15][Toggle off the attack pattern drawing in ExecuteBrainHero()][:"debug visualisation" :"entity system"]
[29:40][Desire to repeatedly punch the same enemy][:collision :"entity system" :run]
[30:16][Consider using a global attack sequence number to makes attacks only hit once][:collision :"entity system" :research]
[31:58][@annonymus][Wouldn't that mean a slow projectile could be invalidated by a later fast projectile?][:collision :"entity system"]
[32:44][Consider making hit boxes activated on only one frame][:collision :"entity system" :research]
[33:46][Spawn multiple heroes][:"entity system" :run]
[34:55][Consider tracking a list of previously overlapping entities][:collision :"entity system" :research]
[39:28][Introduce an entity_collider_group for entity to contain][:collision :"data structure" :"entity system"]
[40:28][Make UpdateAndRenderEntities() compare an Old and New entity_collider_group to detect projectile collisions][:collision :"entity system"]
[46:39][@hmendoza2001][Not from San Francisco, but from Ohio]
[47:09][@hellminmunster][Hey @handmade_hero! I've just started going through this series on YouTube, currently on [~hero/code/code004 Day 004]. So, now that you are 600+ episodes into the series is there anything you want to tell someone just starting?]
[51:49][Make UpdateAndRenderEntities() finally update LastFrameColliders to the NewGroup][:collision :"entity system"]
[52:04][Describe the projectile collision detection loop, considering exit events][:collision :"entity system" :research]
[53:49][Describe a :SIMD version of the projectile collision detection loop][:collision :"entity system" :optimisation :research]
[58:17][Remove unused entity_flags, and split EntityFlag_Collider into EntityFlag_AppliesCollision and EntityFlag_ReceivesCollision][:collision :"entity system"]
[1:01:57][Remove pairwise_collision_rule][:collision :"data structure" :"entity system"]
[1:03:47][@sagian2005][So we can't punch trees…][:collision :"entity system"]
[1:04:38][Remove particle_cel and particle, and CanCollide()][:collision :"data structure" :"entity system" :"particle system"]
[1:05:09][Introduce CollisionResolve()][:collision :"entity system"]
[1:07:02][The snakes have hit points][:collision :"entity system" :run]
[1:07:56][Rename HIT_POINT_SUB_COUNT to HIT_POINT_SUBDIVISIONS][:collision :"entity system"]
[1:09:02][@sagian2005][…but [@cmuratori Casey] can't download Minecraft because the biggest software company in the world wouldn't let him buy the most popular game in the world]
[1:10:49][Implement CollisionResolve(), introducing ApplyDamage()][:collision :"entity system"]
[1:18:22][Make AddPlayer() set EntityFlag_AppliesCollision and SnakePattern set EntityFlag_ReceivesCollision][:collision :"entity system"]
[1:19:45][Punching a snake does no damage][:collision :"entity system" :run]
[1:20:38][Fail to break on ApplyDamage()][:collision :"entity system" :run]
[1:21:10][Break in to the projectile collision detection loop in UpdateAndRenderEntities()][:collision :"entity system" :run]
[1:21:38][Toggle on collision volume drawing in UpdateAndRenderEntities()][:collision :"debug visualisation" :"entity system"]
[1:21:58][The glove obviously collides with the snake][:collision :"debug visualisation" :"entity system" :run]
[1:22:46][Fix SnakePattern() to OR in EntityFlag_ReceivesCollision][:collision :"entity system"]
[1:23:37][Reacquaint ourselves with EntityOverlapsEntity()][:collision :"entity system" :research]
[1:24:46][Separate out the ReceivesCollision and EntityOverlapsEntity() checks in UpdateAndRenderEntities()][:collision :"entity system"]
[1:26:42][Try unsuccessfully to break in to the projectile collision detection loop in UpdateAndRenderEntities()][:collision :"entity system" :run]
[1:27:26][Set EntityFlag_ReceivesCollision to 1 << 3][:collision :"entity system"]
[1:27:55][Scour the projectile collision detection loop for bugs][:collision :"entity system" :research]
[1:28:09][Fix UpdateAndRenderEntities() to set Check to the CheckIter.Entity][:collision :"entity system"]
[1:28:21][Restart the game into our empty room][:collision :"entity system" :run]
[1:28:25][Make CreateOrphanage() generate a snake in the FloorEntranceRoom][:"procedural generation"]
[1:30:43][Try unsuccessfully to punch a snake][:collision :"entity system" :run]
[1:31:14][Break in to the projectile collision detection loop][:collision :"entity system" :run]
[1:32:19][Fix the loop increment direction in ApplyDamage()][:collision :"entity system"]
[1:32:44][Try unsuccessfully to add a breakpoint on ApplyDamage()][:collision :"entity system" :run]
[1:33:05][Break on CollisionResolve() and inspect the disassembly][:asm :collision :"entity system" :run]
[1:33:36][Scour ApplyDamage() for bugs][:collision :"entity system" :research]
[1:34:37][Break on CollisionResolve() in -Od, step through ApplyDamage(), and successfully damage the snake][:asm :collision :"entity system" :run]
[1:36:46][Rebuild in -O2 and successfully damage the snake][:asm :collision :"entity system" :run]
[1:37:31][Enable ApplyDamage() to call DeleteEntity() upon death and only apply damage to active entities, introducing IsActive()][:collision :"entity system"]
[1:40:17][@coffeeeeeeeeeee][Are you going to implement critical hits?][:collision :"entity system"]
[1:41:23][Successfully punch the snake to death][:collision :"entity system" :run]
[1:42:34][Reacquaint ourselves with DeleteEntity()][:"entity system" :research]
[1:43:59][Delete TestWall() and test_wall][:"data structure" :"entity system"]
[1:44:24][Reacquaint ourselves with TransactionalOccupy()][:"entity system" :research]
[1:45:42][Make DeleteEntity() vacate the occupied tile, introducing Vacate()][:"entity system"]
[1:48:58][Punch snakes to death, and successfully walk where they were][:collision :"entity system" :run]
[1:51:54][Remove BoxIndex_Down and BoxIndex_Up, and related stairwell code][:"procedural generation"]
[1:55:07][Hit the Room->GenerationIndex == GenerationIndex assertion in Layout()][:"procedural generation" :run]
[1:55:44][Decrease FloorCount from 4 to 1 in CreateDungeon()][:"procedural generation"]
[1:55:50][Still hit the Room->GenerationIndex == GenerationIndex assertion in Layout()][:"procedural generation" :run]
[1:56:18][Reacquaint ourselves with the Room->GenerationIndex == GenerationIndex assertion in Layout()][:"procedural generation" :research]
[1:57:28][Comment out the Room->GenerationIndex == GenerationIndex assertion in Layout()][:"procedural generation"]
[1:57:39][Hit assertion on PlaceEntityAtP() in StandardLightingPattern()][:"entity system" :"procedural generation" :run]
[1:57:51][Consider making the :"procedural generation" code more direct][:research]
[2:03:32][Consider making the forest area not room-based][:"procedural generation" :research]
[2:05:32][Plan to work on world generation next time][:"procedural generation" :research]
[2:08:49][That's it for today][:speech]
[/video]

View File

@ -0,0 +1,138 @@
[video output=day659 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Immediate-mode Level Generation" vod_platform=youtube id=mCTZHC7u5FE annotator=Miblo]
[0:00][Recap and set the stage for the day working on level generation][:"procedural generation" :speech]
[1:33][@wassimulator][Overlay didn't appear, by the way, [@cmuratori Casey]]
[1:48][Turn on ctray][:admin]
[2:31][Reacquaint ourselves with our declarative Verilog-style level generator][:"procedural generation" :research]
[4:44][Consider switching to a more direct, hand-coded level generation scheme, with lessened :"procedural generation"][:research]
[9:21][Prepare to work on CreateWorld()][:"procedural generation" :research]
[10:20][Thoughts on getting better by productively reorganising systems][:speech]
[11:56][Prepare to work on CreateWorld() (cont.)][:"procedural generation" :research]
[13:08][Comment out the GenerateWorld() part of CreateWorld()][:"procedural generation"]
[13:57][Contextualise our world design thought process with the Legend of Zelda map[ref
site="Thonky.com"
page="First Quest Map"
url=https://www.thonky.com/legend-of-zelda/zelda-map.png]][:"procedural generation" :research]
[21:58][Consider gated world exploration[ref
site="Thonky.com"
page="First Quest Map"
url=https://www.thonky.com/legend-of-zelda/zelda-map.png]][:"procedural generation" :research]
[26:55][@hukutoss][Stairs]
[27:00][Consider gated world exploration (cont.)[ref
site="Thonky.com"
page="First Quest Map"
url=https://www.thonky.com/legend-of-zelda/zelda-map.png]][:"procedural generation" :research]
[28:57][@tk_dev][Yeah, it drains the water]
[29:09][Aim for a world structure similar to The Legend of Zelda[ref
site="Thonky.com"
page="First Quest Map"
url=https://www.thonky.com/legend-of-zelda/zelda-map.png]]
[29:35][What does the whistle do in The Legend of Zelda?][:research]
[32:19][The whistle in The Legend of Zelda drains the lake[ref
author=TYSunny
title="The Legend of Zelda (NES) - 100% Full Game Walkthrough"
publisher=YouTube
url=https://youtu.be/6g2vk8Gudqs?t=4593]][:research]
[33:03][@skeletonstickbug][The flute dries up the lake to open 7, and warps you to completed dungeons from other screens. There's an invisible wall to get to the upper-right corner of the map]
[33:09][@kaffebaronen][Oh, Link to the Past has the wind thing in front of the bird statue]
[33:14][Initial thoughts for us on gated access based on item possession][:"procedural generation" :research]
[34:39][Consider placing tougher dungeons more distant from the start][:"procedural generation" :research]
[36:01][Determine to place dungeons using a tunable blue noise distribution][:"procedural generation" :research]
[38:19][Set up CreateWorld() to generate six dungeons][:"procedural generation"]
[42:10][Thoughts on floating difficulty of rogue-like games][:"game design" :"procedural generation" :research]
[44:29][@Rocket][Hi][:pet]
[45:37][@mr427][You could have hints at the dungeon entrance that lets the player know how difficult it is, so they could show up anywhere]
[46:57][Consider making dungeon exploration less about difficulty between dungeons, but more about how deep you want to go][:"game design" :research]
[48:13][@corpusc][Angband]
[48:21][Depth-choice dungeon exploration in Angband][:"game design" :research]
[49:54][Consider increasing the difficulty per floor, not per dungeon][:"game design" :research]
[50:20][@ablindorphan][Could you make it so that completing dungeons makes future dungeons harder?][:"game design" :research]
[50:49][@phildo3][Won't intro floors become grating by the end of the game, then?][:"game design" :research]
[51:25][Let CreateWorld() possibly generate up to nine dungeons][:"procedural generation"]
[51:39][@j_blow][If intro floors are too long they would be boring, but you want people to have a chance to feel like they actually got more powerful, rather than just ramping difficulty to meet them all the time][:"game design"]
[52:22][@gijlf][If there is any different gameplay based on items / weapons the difficulties can be linked to them. Like you have the sword of fire so the ice dungeon is easier, but the fire one would be harder but never impossible][:"game design"]
[52:29][Set up CreateWorld() to generate its dungeons, the forest and orphanage][:"procedural generation"]
[55:14][@doesntmeananything][I just want the Awesome Button. You press the Button, something Awesome happens. Button -> Awesome]
[55:24][Story time: The Million Dollar Button in Gabriel Knight 3][:speech]
[58:34][Augment world_generator with DungeonLocations for CreateWorld() to set][:"data structure" :"procedural generation"]
[59:56][Consider how to space out dungeons[ref
site="Thonky.com"
page="First Quest Map"
url=https://www.thonky.com/legend-of-zelda/zelda-map.png]][:"procedural generation" :research]
[1:01:17][Make CreateWorld() space out dungeons[ref
site="Thonky.com"
page="First Quest Map"
url=https://www.thonky.com/legend-of-zelda/zelda-map.png]][:"procedural generation"]
[1:09:27][@sagian2005][I got tired of saying "distance squared" all the time and discovered that it's called a quadrance[ref
site=Wikipedia
page="Divine Proportions: Rational Trigonometry to Universal Geometry"
url=https://en.wikipedia.org/wiki/Divine_Proportions:_Rational_Trigonometry_to_Universal_Geometry]][:mathematics]
[1:12:41][@dustingadal][Google ngram search hasn't heard of it[ref
site="Google Ngram Viewer"
page=quadrance
url=https://books.google.com/ngrams/graph?content=quadrance]]
[1:12:52][Make CreateWorld() space out dungeons (cont.)][:"procedural generation"]
[1:15:00][Reflect on our annulus-shaped dungeon placement[ref
site=Wikipedia
page=Annulus
url=https://en.wikipedia.org/wiki/Annulus_(mathematics)]][:mathematics :"procedural generation"]
[1:15:55][Note our need to visualise the dungeon generation][:"debug visualisation" :"procedural generation" :research]
[1:19:25][Toggle on the :"procedural generation" drawing in UpdateAndRenderWorld()][:"debug visualisation"]
[1:20:08][Stub out CreateDungeon(), CreateDungeons(), CreateForest() and CreateOrphanage(), augmenting world_generator with OrphanageLocation and DungeonCount][:"data structure" :"procedural generation"]
[1:24:14][Determine to get a debug map going][:"procedural generation" :research]
[1:24:47][Stretch to infinity, just like Sausage Dog Tends To Infinity[ref
site=Steam
page="Sausage Dog Tends To Infinity"
url=https://store.steampowered.com/app/1299340/Sausage_Dog_Tends_To_Infinity/]][:research]
[1:27:34][Implement CreateDungeon(), introducing PlaceDebugMarker()][:"procedural generation"]
[1:34:58][@dedknd][[@cmuratori Casey] has Bobby McFerrin car vibes today]
[1:37:03][@snoxs49][What is that internal keyword for?][:language]
[1:37:47][@nilsonragee][#define internal static][:language]
[1:38:02][Anticipate the next Bobby McFerrin craze][:speech]
[1:38:42][Toggle off the :camera placement in CreateWorld()][:"procedural generation"]
[1:39:16][:Run straight into the cutscene, because there's no world][:"procedural generation"]
[1:40:01][Determine to vaporise GenRoom()][:"procedural generation" :research]
[1:40:25][@j_blow][I did just show up again]
[1:40:28][What is happening with Sausage Dog Tends To Infinity?]
[1:41:16][@j_blow][I played an early version of it like 34 years ago]
[1:42:24][@j_blow][Release Date Tends to Infinity]
[1:42:44][@snoxs49][Maybe we get Half-Life 3 first]
[1:43:00][Simplify GenerateRoom() for our new generator to call procedurally, delete GenerateWorld() and let CreateWorld() set the :camera position][:"procedural generation"]
[1:46:53][@colax][It's so interesting to see both @j_blow and [@cmuratori Casey] use no autocomplete. For some reason it looks like it's faster than actually having autocomplete. Maybe just typing what we want is faster than the process of our eyes seeing what we want then responding]
[1:48:40][@slava_radko][Visual Studio changes text what I typed instead of suggesting. That's even worse]
[1:49:10][Augment world_generator with StartingRoom for CreateWorld() to set][:"data structure" :"procedural generation"]
[1:50:05][Set up CreateOrphanage() to call GenerateRoom()][:"procedural generation"]
[1:51:17][@j_blow][Almost nobody designs autocomplete any more so that you can just type and not look]
[1:53:03][Make CreateOrphanage() initialise a RoomSpec, removing the gen_apron_spec * from gen_room_spec, and GenRoom()][:"data structure" :"procedural generation"]
[1:55:30][Thoughts on forward-declarations in C / C++][:language :rant :speech]
[1:56:30][@jesobuild][They "fixed it" with C++ 20 and modules][:language]
[1:56:49][@slava_radko][But what would you ship with the :library then?][:language]
[1:59:16][Fix compile errors in GenerateRoom()][:"procedural generation"]
[2:00:05][@valxntinebxtt][That rant on forward-declarations was enough for a sub][:language]
[2:01:38][Make CreateOrphanage() set the RoomVol][:"procedural generation"]
[2:03:00][@kaibutsi][Regarding autocomplete / IntelliSense I think there's a place for it, most likely not in the environment you're currently working in, but it's definitely useful for discoverability when using 3rd-party libraries in languages with stronger type systems]
[2:04:20][Make CreateOrphanage() set the RoomVol (cont.)][:"procedural generation"]
[2:04:37][Launch into our newly-generated room][:"procedural generation" :run]
[2:04:58][Toggle off CollisionVolume drawing in UpdateAndRenderEntities()][:"debug visualisation"]
[2:05:34][Check out our generated world][:"debug visualisation" :"procedural generation" :run]
[2:06:04][Disable GRID_RAY_CAST_DEBUGGING][:lighting]
[2:06:13][Our dungeons are too close together][:"debug visualisation" :"procedural generation" :run]
[2:06:45][Make CreateDungeons() further separate out the dungeons][:"procedural generation"]
[2:07:09][Fall into an infinite loop with our random dungeon placement][:"procedural generation" :run]
[2:07:27][Decrease MinDungeonSeparationDistance from 100 to 10 in CreateDungeons()][:"procedural generation"]
[2:07:47][Dungeons are not distributed evenly][:"procedural generation" :run]
[2:08:08][Tweak the distance values in CreateDungeons()][:"procedural generation"]
[2:09:36][Our dungeons may now be too far away][:"procedural generation" :run]
[2:10:02][Decrease the distance values in CreateDungeons()][:"procedural generation"]
[2:10:32][Our dungeon placement seems not terrible][:"procedural generation" :run]
[2:12:05][Determine to let CreateWorld() use a random seed][:prng :research]
[2:13:44][@graemephi][That was Banjo-Kazooie, I'm sure of it]
[2:14:22][Make CreateWorld() take an InitialSeed, augmenting game_input with Entropy and EntropyRequested][:"data structure" :prng]
[2:18:37][Judicially requesting entropy][:hardware :isa :prng :speech]
[2:21:14][Make WinMainCRTStartup() request Entropy, introducing Win32GetEntropy() using BCryptGenRandom()[ref
site="Microsoft Docs"
page="BCryptGenRandom function (bcrypt.h)"
url=https://docs.microsoft.com/en-us/windows/win32/api/bcrypt/nf-bcrypt-bcryptgenrandom]][:"platform layer" :prng]
[2:27:18][Step in to Win32GetEntropy()][:"platform layer" :prng :run]
[2:27:42][Our :"procedural generation" passes now differ][:run]
[2:29:00][That's good enough for now, with a glimpse into the future][:speech]
[/video]

View File

@ -0,0 +1,104 @@
[video output=day660 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Randomized Overworld Layout" vod_platform=youtube id=pNTpHAo5Pxw annotator=Miblo]
[0:00][Recap and set the stage for the day][:speech]
[1:08][Demo our randomly generated dungeon placement][:"procedural generation" :run]
[2:17][Pull up the original Legend of Zelda map[ref
site="Thonky.com"
page="First Quest Map"
url=https://www.thonky.com/legend-of-zelda/zelda-map.png]][:"procedural generation" :research]
[3:20][Note the proximity-ordered placement of dungeons in The Legend of Zelda[ref
site="Thonky.com"
page="First Quest Map"
url=https://www.thonky.com/legend-of-zelda/zelda-map.png]][:"procedural generation" :research]
[4:09][Recap our plan to make each dungeon increase in difficulty as you go deeper into them][:"procedural generation" :research]
[5:21][Consider how to motivate exploration of our overworld][:"procedural generation" :research]
[6:35][Note the Legend of Zelda's difficulty cues that motivate overworld exploration][:"procedural generation" :research]
[8:24][Why would you care about how you are traversing things?][:"procedural generation" :research]
[8:52][@hniojnuoujbnh][If you think C++ is bad and C better, then why don't you just use C instead of C++?][:language]
[9:44][Why would you care about how you are traversing things? (cont.)][:"procedural generation" :research]
[10:50][Exploration motivation ideas: 1) Enemy generators, with overlapping ranges][:"game design" :"procedural generation" :research]
[14:29][Exploration motivation ideas: 2) Temporary destruction of generators, which strengthen upon regenerating][:"game design" :"procedural generation" :research]
[15:39][@radavandar][So what you get in return for taking out a generator should be worth increasing the long-term difficulty][:"game design" :"procedural generation"]
[16:50][@wheeel][Is there a way to tie the overworld difficulty to the dungeon difficulty system, or is it better to keep separate?][:"game design" :"procedural generation"]
[17:04][Consider making multiple and different routes overlap different generators][:"game design" :"procedural generation" :run]
[19:39][Consider using the dungeon generator for enemy generators][:"procedural generation" :research]
[20:12][Augment world_room with a DebugColor for AddWorldRoom() to set][:"data structure" :"procedural generation"]
[22:15][Our orphanage outline is red][:"debug visualisation" :"procedural generation"]
[22:40][Fix CreateOrphanage() to pass green to PlaceDebugMarker()][:"debug visualisation" :"procedural generation"]
[22:55][With our green orphanage and yellow dungeons, plan to place red enemy generators][:"debug visualisation" :"procedural generation"]
[23:52][@tinspin][By the way, is [~hero Handmade Hero] going to get multiplayer?]
[25:14][Set up CreateForest() to generate enemy generators, augmenting world_generator with GeneratorCount and GeneratorLocations][:"procedural generation"]
[29:04][@dandymcgee][Your :"game design" woes are the essence of my existence as a programmer. I feel your pain in my soul]
[29:33][Consider specifying the notion that "these points in the world should have this many overlapping generators"][:"procedural generation" :research]
[31:25][Introduce world_gen_location and world_gen_location_type, to replace DungeonLocations and GeneratorLocations in world_generator][:"data structure" :"procedural generation"]
[35:14][Update CreateDungeon() to use our new world_gen_location, introducing GetLocation()][:"procedural generation"]
[37:47][@ponkkiz][Anyone know if this error highlighting is public or is it [@cmuratori Casey]'s own thing?]
[38:17][Introduce GetClosestLocationTo() and GetClosestDistanceTo() for CreateDungeons() to use][:"procedural generation"]
[43:53][Set up CreateWorld() to call all the location creation functions, respecifying world_gen_location_type as plain ints rather than flags][:"procedural generation"]
[48:36][Rename CreateForest(), CreateOrphanage() and CreateDungeons() to Layout*(), and introduce CreateMonsterGenerator() and CreateItemRoom()][:"procedural generation"]
[51:08][Introduce PushLocation()][:"procedural generation"]
[53:04][Implement GetClosestLocationTo(), and make CreateWorld() push the orphanage location first][:"procedural generation"]
[59:38][Infinitely loop in our location placement code][:"procedural generation" :run]
[59:50][Scour our location placement code for problems][:"procedural generation" :research]
[1:01:34][Enable GetClosestLocationTo() to handle exclusion types, introducing Matches() and FlagOf()][:"procedural generation"]
[1:05:14][Hit a write access violation][:"procedural generation" :run]
[1:05:51][Hit the Gen->LocationCount assertion in PushLocation()][:"procedural generation" :run]
[1:05:59][Fix LayoutOverworld() to increment PlacedDungeonCount(), relieving it of using dungeons as an exclusion type][:"procedural generation"]
[1:06:19][:Run successfully in -Od][:"procedural generation"]
[1:06:35][:Run successfully in -O2][:"procedural generation"]
[1:06:47][Consider generalising our half-annulus point-picking code][:"procedural generation" :research]
[1:09:07][Drop frames][:admin]
[1:10:24][Quick break][:admin]
[1:10:30][:afk]
[1:12:08][Return and eyeball the dropped frames counter][:admin]
[1:13:35][Introduce PickPointInAnnulus() and world_gen_annulus][:"data structure" :"procedural generation"]
[1:22:46][Our dungeons remain dispersed along a half-annulus][:"procedural generation" :run]
[1:22:54][Make LayoutOverworld() generate item rooms using PickPointInAnnulus()][:"procedural generation"]
[1:24:54][Hit our max iteration assertion in PickPointInAnnulus()][:"procedural generation" :run]
[1:24:59][Fix LayoutOverworld() to strew items along a different annulus][:"procedural generation"]
[1:25:34][We now have item rooms, but can still hit our max iteration assertion in PickPointInAnnulus()][:"procedural generation" :run]
[1:26:02][Consider improvements to PickPointInAnnulus()][:"procedural generation" :research]
[1:27:29][Switch PickPointInAnnulus() to use a random angle and distance, to discard fewer points][:"procedural generation"]
[1:30:13][Locations are placed behind the orphanage][:"procedural generation" :run]
[1:30:42][Augment world_generator with an OrphanageYLine for PickPointInAnnulus() to clip to, introducing IsInForest()][:"procedural generation"]
[1:32:54][Hit our max iteration assertion in PickPointInAnnulus()][:"procedural generation" :run]
[1:33:11][Decrease MinDistFromExistingLoc from 40 to 20 for item rooms][:"procedural generation"]
[1:33:17][We successfully place locations][:"procedural generation" :run]
[1:33:46][Establish the notion of min distance from everything / specific, introducing world_gen_filter for world_gen_annulus to contain][:"data structure" :"procedural generation"]
[1:34:59][Enable PickPointInAnnulus() to apply our new world_gen_filter][:"procedural generation"]
[1:39:53][Locations may only be placed far from their same type but near different types][:"procedural generation" :run]
[1:40:33][Determine to add the monster generators][:"procedural generation" :research]
[1:41:49][Make LayoutOverworld() generate enemy generators, augmenting world_gen_location with OverlappingGeneratorCount][:"data structure" :"procedural generation"]
[1:52:45][Hit our max iteration assertion in PickPointInAnnulus()][:"procedural generation" :run]
[1:52:52][Temporarily decrease MinDist from 10 to 0 for the monster generator filter in LayoutOverworld()][:"procedural generation"]
[1:53:02][Hit our max iteration assertion in PickPointInAnnulus()][:"procedural generation" :run]
[1:53:08][Revert MinDist in LayoutOverworld()][:"procedural generation"]
[1:53:27][Try making LayoutOverworld() place monster generators at our annulus-dispersal centroids][:"procedural generation"]
[1:53:56][Crash on PushLocation()][:"procedural generation" :run]
[1:54:03][Scour our monster generator placement code for bugs][:"procedural generation" :research]
[1:54:26][Hit our Gen->LocationCount assertion in PushLocation()][:"procedural generation" :run]
[1:54:44][Count up our locations][:"procedural generation" :research]
[1:55:11][Make LayoutOverworld() add 1 to our MaxLocationCount for the orphanage][:"procedural generation"]
[1:55:21][:Run successfully in -Od][:"procedural generation"]
[1:55:27][In -O2, our monster generators are all placed in the same location][:"procedural generation" :run]
[1:55:52][Try letting LayoutOverworld() place monster generators at the centroid of dungeons and item rooms without overlapping generators][:"procedural generation"]
[1:57:21][Our monster generators are placed better][:"procedural generation" :run]
[1:57:35][Desire random location picking for monster generators][:"procedural generation" :research]
[1:59:34][Let LayoutOverworld() place monster generators along their annuli][:"procedural generation"]
[1:59:53][We have plenty more locations][:"procedural generation" :run]
[2:00:10][Increase MonsterGeneratorCount from between 12 and DungeonCount + ItemRoomCount in LayoutOverworld()][:"procedural generation"]
[2:01:26][Hit our max iteration assertion in PickPointInAnnulus()][:"procedural generation" :run]
[2:01:35][Let LayoutOverworld() place monster generators around other monster generators][:"procedural generation"]
[2:01:51][Successfully place all locations][:"procedural generation" :run]
[2:02:44][Increase MinDist from 10 to 20 for the monster generator filter in LayoutOverworld()][:"procedural generation"]
[2:02:53][Hit our max iteration assertion in PickPointInAnnulus()][:"procedural generation" :run]
[2:03:09][Make PickPointInAnnulus() try 10× more points][:"procedural generation"]
[2:03:20][Successfully place all locations, with the determination to place paths next week][:"procedural generation" :run]
[2:04:29][Plug the [~hero Handmade Hero] pre-order[ref
site="Handmade Hero"
url=https://handmadehero.org] and Molly Movie Club[ref
site="Molly Movie Club"
url=https://www.mollymovieclub.com]][:research]
[2:07:16][That's about it][:speech]
[2:07:30][@technicbeam][Saves me from having to watch Dune]
[2:07:34][Take it easy, everybody][:speech]
[/video]

View File

@ -0,0 +1,141 @@
[video output=day661 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Connecting the Overworld Map" vod_platform=youtube id=mt4Z9RkylF0 annotator=Miblo]
[0:00][Recap and set the stage for the day][:speech]
[0:35][Demo our sparse overworld layout][:"procedural generation" :run]
[0:59][Thicken the location outline from 0.01 to 0.1][:"debug visualisation" :"procedural generation"]
[1:22][Demo our annulus-based location regeneration][:"procedural generation" :run]
[5:49][Determine to connect locations with paths][:"procedural generation" :run]
[7:24][@orclockx][Is [@cmuratori he] using compute shaders?][:rendering]
[7:54][@dustdrown][For the entire :rendering I think is what he meant]
[8:08][Determine to compute a connectivity graph for our locations][:"procedural generation" :run]
[9:50][Check the chat][:admin]
[10:29][Compute shaders][:rendering :simd :speech]
[11:36][@roblon][These questions are so off-topic]
[12:23][Overflow the :"debug system"][:run]
[13:46][Consider clustering up locations][:"procedural generation" :research]
[15:24][Determine to create waypoint locations][:"procedural generation" :research]
[15:48][Demo our need for waypoints][:"procedural generation" :run]
[17:06][Add a WorldLoc_NavRoom and introduce CreateNavRoom()][:"procedural generation"]
[18:20][Determine to fill gaps in the map with nav rooms][:"procedural generation" :run]
[18:46][Enable LayoutOverworld() to generate nav rooms][:"procedural generation"]
[21:01][Hit our max iteration assertion in PickPointInAnnulus()][:"procedural generation" :run]
[21:33][Let the world generator complete if locations cannot be placed, augmenting world_gen_annulus with RequirePlacement, and introducing world_gen_pick_v2][:"data structure" :"procedural generation"]
[26:42][We have one green waypoint, standing at the edge][:"procedural generation" :run]
[26:53][Decrease MinDist from 60 to 30 for the nav rooms in LayoutOverworld()][:"procedural generation"]
[27:07][We have many more waypoints][:"procedural generation" :run]
[27:38][Hit our max iteration assertion in PickPointInAnnulus()][:"procedural generation" :run]
[27:55][Desire a better annulus picker, and regenerate many layouts][:"procedural generation" :run]
[28:28][Determine to connect nearby and unobstructed pairs of rooms][:"procedural generation" :research]
[31:20][Confirm that we can draw lines][:rendering :research]
[31:50][Introduce world_room_connection, and augment world with ConnectionCount and Connections][:"data structure" :"procedural generation"]
[32:46][Set up LayoutOverworld() to connect locations][:"procedural generation"]
[37:08][@doesntmeananything][WutFace]
[38:14][Augment world_room_connectionw with DebugColor and introduce AddWorldConnection(), for LayoutOverworld() to call][:"data structure" :"procedural generation"]
[40:49][We see no location connections][:"procedural generation" :run]
[40:56][Make UpdateAndRenderWorld() draw the location connections][:"debug visualisation" :"procedural generation"]
[45:04][All the locations are connected, but a blue room overlaps the orphanage][:"debug visualisation" :"procedural generation" :run]
[45:47][Prevent GenerateRoom() from creating a WorldRoom][:"procedural generation"]
[46:47][That blue room has gone][:"procedural generation" :run]
[47:09][Specify a location connection criterion in LayoutOverworld(): 1) Locations must be nearby][:"procedural generation"]
[49:00][All the locations remain connected][:"procedural generation" :run]
[49:08][Fix our "nearby" criterion in LayoutOverworld()][:"procedural generation"]
[49:19][Most rooms are not connected][:"procedural generation" :run]
[49:29][Increase our "nearby" location criterion from 30 to 60][:"procedural generation"]
[49:38][Our rooms are mostly, but not entirely, connected][:"procedural generation" :run]
[53:43][Determine to repair disconnections, using a disjoint-set forest][:"procedural generation" :run]
[54:20][Determine to forcibly connect the closest two rooms of disjoint islands][:"procedural generation" :research]
[55:05][Regenerate many disjoint layouts][:"procedural generation" :run]
[56:04][Make LayoutOverworld() draw location connections of satellites in purple, augmenting world_gen_location with ConnectedToOrphanage][:"debug visualisation" :"procedural generation"]
[1:01:41][Immediately hit our !B->ConnectedToOrphanage assertion in LayoutOverworld()][:"procedural generation" :run]
[1:01:47][Propagate our ConnectedToOrphanage checks in LayoutOverworld()][:"procedural generation"]
[1:03:30][Location connections of satellites are purple][:"procedural generation" :run]
[1:04:01][Make LayoutOverworld() instead draw all rooms of satellites in purple][:"debug visualisation" :"procedural generation"]
[1:06:21][Our satellite rooms are not purple][:"debug visualisation" :"procedural generation" :run]
[1:06:41][Make CreateWorld(), rather than LayoutOverworld(), colour satellite rooms in purple][:"debug visualisation" :"procedural generation"]
[1:07:24][Now all rooms are purple][:"debug visualisation" :"procedural generation" :run]
[1:07:35][Fix the !Loc->ConnectedToOrphanage test in CreateWorld()][:"debug visualisation" :"procedural generation"]
[1:07:48][Satellite rooms are now coloured purple][:"debug visualisation" :"procedural generation" :run]
[1:08:29][Enable LayoutOverworld() to connect satellite locations to the orphanage's locations][:"procedural generation"]
[1:10:30][@dmviper][Hey [@cmuratori Casey], I just found the Molly Rocket channel on YouTube and I'm only on day 7, but I wanted to thank you for the great content!]
[1:10:35][Enable LayoutOverworld() to connect satellite locations to the orphanage's locations (cont.)][:"procedural generation"]
[1:13:28][We have an unconnected satellite][:"debug visualisation" :"procedural generation" :run]
[1:13:55][Double-check our satellite connection code][:"procedural generation" :research]
[1:14:41][Fix typo in the satellite connection code's inner loop][:"procedural generation"]
[1:14:53][Potential satellites are now connected][:"debug visualisation" :"procedural generation" :run]
[1:18:08][Temporarily remove nav rooms][:"procedural generation"]
[1:18:23][It's better without nav rooms][:"procedural generation" :run]
[1:18:40][Let LayoutOverworld() create fewer nav rooms][:"procedural generation"]
[1:18:55][Sometimes extra rooms fill in the world too much][:"procedural generation" :run]
[1:19:04][Hit our Pick.PassedFilters assertion in LayoutOverworld()][:"procedural generation" :run]
[1:19:36][Consider a world with fewer nav rooms to feel better][:"procedural generation" :run]
[1:20:16][Let LayoutOverworld() create between 4 and the DungeonCount nav rooms][:"procedural generation"]
[1:20:41][Consider forcing nav rooms to have multiple connections]
[1:21:46][@wheeel][Is a nav room <-> nav room connection also redundant?][:"procedural generation"]
[1:21:59][@technicbeam][Somehow I think I would have set the startup view to be way zoomed out ages ago, if I were testing this]
[1:23:54][@mtsmox][Q: Maybe just remove nav rooms with one connection?][:"procedural generation"]
[1:24:31][Determine to forcibly connect nav rooms following the trajectory from their inbound connection, removing ones where this is impossible][:"procedural generation" :run]
[1:26:10][Enable LayoutOverworld() to remove the connection of all orphaned nav rooms][:"procedural generation"]
[1:28:13][Orphaned nav rooms are now jettisoned][:"procedural generation" :run]
[1:29:35][Enable LayoutOverworld() to remove the connections of "jointly orphaned" nav rooms][:"procedural generation"]
[1:32:21][Orphaned nav rooms are no longer jettisoned][:"procedural generation" :run]
[1:32:51][Double-check our orphaned nav room jettisoning code][:"procedural generation" :research]
[1:33:55][Orphaned nav rooms are mostly left intact][:"procedural generation" :run]
[1:34:37][Fix LayoutOverworld() to remove the connections of orphaned nav rooms with 0 or 1 connections][:"procedural generation"]
[1:34:50][We can delete valuable nav rooms][:"procedural generation" :run]
[1:35:25][Enable LayoutOverworld() to remove the connection only of nav rooms with one connection][:"procedural generation"]
[1:36:23][Tolerate exterior "jointly orphaned" nav rooms][:"procedural generation" :run]
[1:36:54][Hit our Pick.PassedFilters assertion in LayoutOverworld()][:"procedural generation" :run]
[1:37:16][Our connections are nice][:"procedural generation" :run]
[1:37:28][Specify a location connection criterion in LayoutOverworld(): 2) Connections must not pass too close to other locations][:"procedural generation"]
[1:40:42][Introduce DistanceBetweenLineSegmentAndPointSq()][:mathematics]
[1:51:49][We still produce obstructed connections][:"procedural generation" :run]
[1:52:08][Make LayoutOverworld() draw viable connections green on nonviable ones red][:"debug visualisation" :"procedural generation"]
[1:53:25][Double-check DistanceBetweenLineSegmentAndPointSq()][:mathematics :research]
[1:54:19][Determine to debug nonviable connections][:"procedural generation" :run]
[1:54:52][@wheeel][Muted?]
[1:55:26][Determine to debug nonviable connections (cont.)][:"procedural generation" :research]
[1:56:06][@multiplybyone][I don't think clamping to between zero and one will give the same as doing the inner product with the normalized vectors. I'm not 100% sure what you're doing, though, so sorry if bad suggestion][:mathematics]
[1:56:33][Fix DistanceBetweenLineSegmentAndPointSq() to compute the distance along the line's perpendicular][:mathematics]
[2:00:59][We still produce obstructed connections][:"procedural generation" :run]
[2:01:13][Double-check DistanceBetweenLineSegmentAndPointSq()][:mathematics :research]
[2:01:40][Fix DistanceBetweenLineSegmentAndPointSq() to multiply in the Dir to the ClosestP][:mathematics]
[2:01:50][We now identify obstructed connections][:"procedural generation" :run]
[2:02:44][Increase the connection obstruction radius from 10 to 20 in LayoutOverworld()][:"procedural generation"]
[2:02:54][We identify more connections to be obstructed][:"procedural generation" :run]
[2:03:33][That's it][:"procedural generation" :research]
[2:03:51][Enjoy the maps][:"procedural generation" :run]
[2:05:08][Make LayoutOverworld() set orphaned rooms as WorldLoc_None to prevent CreateWorld() from creating them][:"procedural generation"]
[2:05:37][We have no unconnected rooms][:"procedural generation" :run]
[2:05:45][@johnm___][What's up with the boxes with no connections?][:"procedural generation"]
[2:06:05][Temporarily prevent LayoutOverworld() from setting orphaned rooms as WorldLoc_None][:"procedural generation"]
[2:06:15][Describe orphaned nav rooms removal][:"procedural generation" :run]
[2:07:37][Temporarily prevent LayoutOverworld() from removing the connections of orphaned nav rooms][:"procedural generation"]
[2:07:59][Describe orphaned nav rooms removal (cont.)][:"procedural generation" :run]
[2:08:28][Let LayoutOverworld remove the connections of orphaned nav rooms][:"procedural generation"]
[2:08:48][Describe orphaned nav rooms removal (cont.)][:"procedural generation" :run]
[2:09:02][Let LayoutOverworld() set orphaned rooms as WorldLoc_None][:"procedural generation"]
[2:09:14][Describe orphaned nav rooms removal (cont.)][:"procedural generation" :run]
[2:09:58][@brian_nevec][Will the world still be infinite?][:"procedural generation"]
[2:10:28][@frizi09][Would it correctly remove a leaf sequence of multiple nav rooms?][:"procedural generation"]
[2:11:11][Admire our maps][:"procedural generation" :run]
[2:11:38][@fallen_spirit][Is the plan to still have smooth transitions between rooms, or will the player "teleport" between rooms?][:camera :"procedural generation"]
[2:12:28][@fallen_spirit][There is just a lot of space between rooms now][:"procedural generation"]
[2:14:32][@samoth2401][I guess a way to not have a sqrt is to not normalize, do the inner product, divide the result by LengthSq(Delta), Clamp01 and multiply t by Delta?][:mathematics]
[2:16:10][Compare SQRTPS, DIVPS, RCPPS and RSQRTPS :performance[ref
site=uops.info
url=https://uops.info/table.html]][:research]
[2:18:58][Consider simplifications to DistanceBetweenLineSegmentAndPointSq()][:mathematics :research]
[2:21:09][@vulpanul][Sorry to disturb the train of thought. Meow[ref
site="Meow the Infinite"
url=https://meowtheinfinite.com/] finally arrived this month and we loved it. Any hints on when the next volume will be out?]
[2:28:31][@tomisqi][What other projects are you working on?]
[2:29:40][@bulmanator][The print quality is second to none, it's so good!]
[2:32:37][Plug Meow the Infinite[ref
site="Meow the Infinite"
url=https://meowtheinfinite.com/]][:research]
[2:35:47][@technicbeam][Does violence and sex improve things?]
[2:36:10][That's it for today, with a glimpse into the future filling in entities][:"procedural generation" :speech]
[2:37:21][@infernalagent][Why didn't you do this generator backwards, like with the Witness grass?][:"procedural generation"]
[2:37:45][@infernalagent][Creating the connections first][:"procedural generation"]
[2:38:24][@infernalagent][Yeah, and then you do not need to cull the connections][:"procedural generation"]
[2:41:54][Thank you, everyone][:speech]
[/video]

View File

@ -0,0 +1,130 @@
[video output=day662 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Generating Entities from Layouts" vod_platform=youtube id=F1b0daEyh2M annotator=Miblo]
[0:01][Recap and set the stage for the day][:"procedural generation" :speech]
[0:58][Demo our procedurally laid-out overworld][:"procedural generation" :run]
[4:38][Generate a new map, with the determination to place environmental entities respecting the connectivity graph][:"procedural generation" :run]
[5:29][Environment generation: 1) Using the connection line literally][:"procedural generation" :run]
[6:58][Environment generation: 2) "Jankifying" or making the lines meander][:"procedural generation" :run]
[8:02][Determine to start by following the lines literally][:"procedural generation" :run]
[9:41][Consider the performance of our entity structure][:"entity system" :run]
[10:30][Prepare to generate our connected forest, encompassed by an impenetrable wall][:"procedural generation" :run]
[12:15][Pull up the code for CreateWorld()][:"procedural generation" :research]
[12:27][We could generate stuff in the other room types][:"procedural generation" :run]
[12:37][Make CreateItemRoom() call GenerateRoom()][:"procedural generation"]
[12:59][Our item rooms are not close enough to be paged in][:"entity system" :"procedural generation" :run]
[13:23][Let CreateOrphanage() generate a far larger room][:"procedural generation"]
[13:48][There's a nav room in our orphanage][:"procedural generation" :run]
[13:56][Make CreateNavRoom() call GenerateRoom()][:"procedural generation"]
[14:17][Our nav room is generated, but offset][:"procedural generation" :run]
[14:57][Reacquaint ourselves with CreateNavRoom() and PlaceDebugMarker()][:"procedural generation" :research]
[16:03][Our nav rooms are shifted inconsistently][:"procedural generation" :run]
[16:47][Wonder if we have a scaling disparity between the debug marker drawing and entity placement][:"procedural generation" :run]
[18:19][Reacquaint ourselves with the debug marker drawing in UpdateAndRenderWorld(), to see it is done in a RenderGroup][:"debug visualisation" :"entity system" :"procedural generation" :research]
[18:54][Expect our room markers to shift with the simulation region][:"debug visualisation" :"entity system" :"procedural generation" :run]
[19:40][Try to disable boundaries by making CreateOrphanage() set RoomSpec.Outdoors to true][:"procedural generation"]
[20:16][We still have boundary trees][:"procedural generation" :run]
[20:31][Try to disable tree creation by making GenerateRoom() set OnEdge to false][:"procedural generation"]
[20:48][Our room markers do not shift with the simulation region][:"debug visualisation" :"entity system" :"procedural generation" :run]
[22:34][Reconsider it to be a scaling disparity][:"procedural generation" :research]
[24:49][Our debug markers and grid edits occur in totally different spaces][:"procedural generation" :research]
[26:17][Determine to line up our debug markers and grid edits][:"procedural generation" :research]
[27:39][Change PlaceDebugMarker() to position it using ChunkPositionFromTilePosition()][:"debug visualisation" :"procedural generation"]
[30:51][Our map is maybe too big][:"debug visualisation" :"procedural generation" :run]
[31:03][Make PlaceDebugMarker() scale the positions by 0.5][:"debug visualisation" :"procedural generation"]
[31:30][Our map is probably more what we want][:"debug visualisation" :"procedural generation" :run]
[31:44][Move the scaling factor from PlaceDebugMarker() out to LayoutOverworld()][:"debug visualisation" :"procedural generation"]
[33:31][We now produce over-long and, again, obstructed connections][:"procedural generation" :run]
[34:15][Fix LayoutOverworld() to apply the Scale to GeneratorRadius][:"debug visualisation" :"procedural generation"]
[35:57][Generate maps][:"procedural generation" :run]
[36:12][Generate a buggy map][:"procedural generation" :run]
[36:33][Wonder if LayoutOverworld() gave up in a loop][:"procedural generation" :research]
[36:54][Decrease the Scale from 1 to 0.5 in LayoutOverworld()][:"procedural generation"]
[37:10][Our map is much tighter, but we still generate obstructed connections][:"procedural generation" :run]
[37:34][Wonder if making PlaceDebugMarker() use ChunkPositionFromTilePosition() caused our obstructed connection generation][:"procedural generation" :research]
[38:22][Revert PlaceDebugMarker() to not use ChunkPositionFromTilePosition()][:"debug visualisation" :"procedural generation"]
[38:44][Generate maps][:"procedural generation" :run]
[38:51][Generate a buggy map][:"procedural generation" :run]
[39:46][Scour CreateWorld() for any uninitialised values][:"procedural generation" :research]
[41:33][Scour LayoutOverworld() for a cause of our obstructed connections][:"procedural generation" :research]
[43:09][Generate maps, and manage to get a buggy one on startup][:"procedural generation" :run]
[44:06][Scour the AddWorldConnection() loop in LayoutOverworld() for bugs][:"procedural generation" :research]
[45:00][Scour DistanceBetweenLineSegmentAndPointSq() for bugs][:mathematics :research]
[47:10][Scan through LayoutOverworld(), describing the white and purple line colouring, and AddWorldConnection()][:"procedural generation" :research]
[48:12][Seek a pattern in our buggy map generation][:"procedural generation" :run]
[49:49][Wonder if our rooms got moved after connection][:"procedural generation" :research]
[51:20][Try disabling the if(Viable) check in LayoutOverworld() to aid debugging our obstructed connection generation][:"procedural generation"]
[52:03][Check out our rejected, red connection lines][:"procedural generation" :run]
[53:22][Check out our rejected, red connection lines on a buggy map][:"procedural generation" :run]
[53:52][Try toggling off the connection removal of unnecessary nav rooms in LayoutOverworld()][:"procedural generation"]
[55:11][Generate a plethora of non-buggy maps][:"procedural generation" :run]
[55:43][Wonder if there actually is a room 0][:"procedural generation" :research]
[55:51][Generate another plethora of non-buggy maps][:"procedural generation" :run]
[56:23][Investigate how setting the two rooms to 0 can generate obstructed connections][:"procedural generation" :research]
[58:48][It is an indexing bug: Setting LocA->Type to WorldLoc_None, thus not creating a room, throws the connection indices off-by-1][:language :"procedural generation" :research]
[1:00:35][Leave the connection removal of unnecessary nav rooms toggled off, and add a TODO to track indices correctly][:"procedural generation"]
[1:03:36][Enable LayoutOverworld() to scale the map after the fact][:"procedural generation"]
[1:04:39][Generate a map][:"procedural generation" :run]
[1:04:44][Decrease the WorldScale from 1 to 0.5 in LayoutOverworld()][:"procedural generation"]
[1:04:55][Our world is now more smooshed][:"procedural generation" :run]
[1:05:09][Introduce TileFromPoint() to line up the debug markers and grid edits coordinate systems][:"procedural generation"]
[1:07:45][Make CreateOrphanage() use TileFromPoint()][:"procedural generation"]
[1:08:47][Our orphanage remains lined up][:"procedural generation" :run]
[1:08:53][Make CreateItemRoom(), CreateMonsterGenerator() and CreateDungeon() use TileFromPoint()][:"procedural generation"]
[1:09:45][Our rooms' generated entities all line up with their debug markers][:"debug visualisation" :"procedural generation" :run]
[1:10:13][Determine to fill in the connective tissue between rooms][:"procedural generation" :run]
[1:15:17][Consider subdividing the map into a coarse grid and rasterising each populated region][:"procedural generation" :run]
[1:16:14][Make LayoutOverworld() compute the union between all locations, for CreateWorld() to generate as a world room, augmenting world_generator with WorldBounds][:"data structure" :"procedural generation"]
[1:22:45][Hit a read access violation in CreateWorld()][:"procedural generation" :run]
[1:23:12][Fix CreateWorld() to call EndWorldGen() at the very end][:"procedural generation"]
[1:23:24][Our map is now outlined][:"procedural generation" :run]
[1:23:36][Increase the WorldScale from 0.5 to 0.7 in LayoutOverworld()][:"procedural generation"]
[1:23:58][We now have a perimeter within which we may march and generate entities][:"procedural generation" :run]
[1:24:43][Determine to march through and rasterise everything][:"procedural generation" :run]
[1:25:46][Reduce CreateNavRoom(), CreateItemRoom(), CreateMonsterGenerator() and CreateDungeon() to only call PlaceDebugMarker()][:"debug visualisation" :"procedural generation"]
[1:26:25][Our rooms are no longer filled in][:"procedural generation" :run]
[1:26:31][Introduce GenerateBlock() to generate environmental entities throughout the block, for CreateOrphanage() to call][:"procedural generation"]
[1:39:54][Hit our !World->UnpackedIsOpen assertion in EnsureRegionIsUnpacked()][:"procedural generation" :run]
[1:40:01][Make GenerateBlock() call EndGridEdit() at the very end][:"procedural generation"]
[1:40:27][The :camera begins not set to anything][:"procedural generation" :run]
[1:40:34][Make GenerateBlock() put the :camera somewhere][:"procedural generation"]
[1:41:21][We have a patch of grass as the orphanage][:"procedural generation" :run]
[1:41:42][Make GenerateBlock() place trees on non-walkable tiles, using IsOnEdge() as the IsWalkable() test][:"procedural generation"]
[1:42:39][Trees are placed around the edge][:"procedural generation" :run]
[1:42:54][Make GenerateBlock() use the room locations and connection lines as its IsWalkable() tests, to generate environmental entities there][:"procedural generation"]
[1:46:50][Our orphanage remains as a patch of grass][:"procedural generation" :run]
[1:47:05][Make CreateWorld() rather than CreateOrphanage() call GenerateBlock()][:"procedural generation"]
[1:47:47][@nickito97][I'm scared of doing anything with enough tomato in a seasoned wok][:cookery]
[1:47:57][Make CreateWorld() subdivide the world into blocks, on which to call GenerateBlock()][:"procedural generation"]
[1:52:28][Crash in AddEntity()][:"procedural generation" :run]
[1:52:45][Compile in -Od][:language]
[1:53:02][Hit the InvalidCodePath in AcquireUnpackedEntitySlot()][:"entity system" :run]
[1:53:21][Check EndGridEdit() for bugs related to AcquireUnpackedEntitySlot()][:"entity system" :research]
[1:54:20][Investigate our InvalidCodePath hit in AcquireUnpackedEntitySlot()][:"entity system" :run]
[1:57:48][Break on the CountExceeded check in EnsureRegionIsUnpacked()][:"entity system" :run]
[1:59:05][Try unsuccessfully to break on the IsOutsideVolume assertion in EnsureRegionIsUnpacked() before hitting the InvalidCodePath in AcquireUnpackedEntitySlot()][:"entity system" :run]
[2:01:59][Fix CreateWorld() to subdivide the world into different blocks to pass to GenerateBlock()][:"procedural generation"]
[2:02:30][:Run successfully without hitting an InvalidCodePath][:"entity system"]
[2:02:53][Fix CreateWorld() to offset the block subdivisions by MinTileI][:"procedural generation"]
[2:03:14][@filiadelski][Everyone is fired]
[2:03:16][@thesandvichmaker][Just throw any leftover vegetables in][:cookery]
[2:03:19][Our room connections are filled with environmental entities, but entities do not get streamed in][:"entity system" :"procedural generation" :run]
[2:04:02][Uncomment the hero's head light in AddPlayer()][:"entity system" :lighting]
[2:04:45][Our room connections remain filled correctly, only lacking entity streaming][:"entity system" :"procedural generation" :run]
[2:06:59][Decrease BlockDim from 32 to 16 in CreateWorld()][:"procedural generation"]
[2:07:24][Hit a write access violation on AcquireUnpackedEntitySlot() upon moving between sim regions][:"entity system" :"procedural generation" :run]
[2:07:56][:Run in -Od and hit the InvalidCodePath in AcquireUnpackedEntitySlot()][:"entity system" :run]
[2:08:47][End it there][:speech]
[2:09:02][Compile in -O2, and consider removing the 3rd dimension][:language]
[2:09:18][Traverse our forest][:"procedural generation" :run]
[2:09:55][Inflate our WorldBounds in LayoutOverworld()][:"procedural generation"]
[2:10:26][Traverse our forest][:"procedural generation" :run]
[2:10:38][Determine to remove Z next week][:speech]
[2:10:50][Consider our start-up :performance to be good][:"procedural generation" :run]
[2:11:46][@sagian2005][Is there going to be a stream next week? I actually try to plan my Sunday around the stream]
[2:11:54][Plug the Molly Movie Club[ref
site="Molly Movie Club"
url=https://www.mollymovieclub.com/] stream here[ref
site=Twitch
page="Molly Rocket"
url=https://twitch.tv/molly_rocket] on Friday 30th September 2022][:speech]
[2:13:21][Determine to remove Z and update entity streaming next week][:speech]
[/video]

View File

@ -0,0 +1,124 @@
[video output=day663 member=cmuratori stream_platform=twitch stream_username=handmade_hero project=code title="Simplifying Entity Storage, Part I" vod_platform=youtube id=LR3THwlv_r4 annotator=Miblo]
[0:00][Recap and set the stage for the day][:speech]
[0:34][Demo our updated world generation without entity unpacking][:"entity system" :"procedural generation" :run]
[1:19][Determine to simplify entity storage][:"entity system" :speech]
[4:12][Describe our entity packing system][:compression :"entity system" :speech]
[5:51][Plan our entity storage simplification][:"entity system" :speech]
[7:21][Remove ChunkZ from world_chunk and world_position][:"data structure" :"entity system"]
[11:13][The game runs just the same][:"entity system" :run]
[12:22][Reacquaint ourselves with the TODO in world_position][:"entity system" :research]
[12:59][Consider removing the ChangeTicket ticket_mutex from world][:"data structure" :research :threading]
[17:27][Plan to simplify the world][:"data structure" :"entity system" :research]
[18:46][Reorganise Rooms and Connections to the end of the world][:"data structure" :"debug system" :"entity system"]
[19:03][Describe our rooms and connections :"debug visualisation"][:"procedural generation" :run]
[19:48][Reacquaint ourselves with the entity packing system][:"data structure" :"entity system" :research]
[22:07][Consider switching to an updatable entity hash table: 1) Removing the sim_region][:"data structure" :"entity system" :research]
[24:16][Consider switching to an updatable entity hash table: 2) Moving the unpacked stuff from the world into the sim_region][:"data structure" :"entity system" :research]
[25:15][Consider the need to handle distant unpacked sim regions, e.g. free-exploring couch co-op][:"entity system" :research]
[27:30][Consider the need for spatial partitioning][:"entity system" :research]
[30:12][@nsaibot][Usually I take a nap to think about things]
[30:41][Consider the need for spatial partitioning (cont.)][:"entity system" :research]
[32:40][Reacquaint ourselves with the world's LastUsedEntityStorageIndex][:"data structure" :"entity system" :research]
[33:34][Respecify world_entity_block as packed_entity_block, and remove FirstFree from the world][:"data structure" :"entity system"]
[36:28][Introduce unpacked_entity_block for world_chunk to contain][:"data structure" :"entity system"]
[40:27][Consider moving EntityHash from sim_region to the world, for entity ID lookup][:"data structure" :"entity system" :research]
[41:12][Consider switching entity hash collision resolution from probing to chaining][:"entity system" :hashing :research]
[43:39][Consider removing entity ID lookup entirely in favour of spatial querying][:"entity system" :research]
[45:14][Briefly :run the game]
[45:26][Speculatively remove GetEntityByID()][:"entity system" :hashing]
[46:35][Plan entity storage simplification: 1) Remove traversables in favour of grid square occupation][:"entity system" :movement :research]
[47:22][@landosensei][Amazing content! I like the theme color palette. I would like to know: which theme are you using?]
[48:05][@alparkaan][Can you share the theme? The one in the source files is outdated[ref
site="Dion-Systems / 4coder"
page="4coder / ship_files / themes"
url=https://github.com/Dion-Systems/4coder/tree/master/ship_files/themes]]
[50:09][@ponkkiz][I always thought it was [@ryanjfleury Ryan]'s theme. It looked very similar]
[50:18][@lesnariv][The repo is archived now. I don't think you can submit it]
[50:23][Copy theme-casey.4coder into the [~hero Handmade Hero] directory][:admin]
[51:02][@tarriest_python][I don't know if it will get merged, but I have a repo with just ~4coder themes if you wanna submit it there. It's where most people get pointed to from the ~4coder discord]
[51:47][@tarriest_python][I have access to the [~hero Handmade Hero] code so as long as your happy with it being public I can chuck it in when it goes up]
[51:59][Remove StompOnEntity()][:"entity system" :movement]
[52:18][Determine to change the idea of traversables to be based on an actual position][:"entity system" :movement :research]
[53:41][Plug OALabsLive[ref
site=Twitch
page=OALabsLive
url=https://www.twitch.tv/oalabslive]][:speech]
[55:31][@an0nymal][Just wondering, is 32-bit int + float a quick and dirty way to get around floating point precision issues (assuming you only need a small range of the float within any 32-bit ID?]
[59:12][Plan our removal of traversables][:"entity system" :movement :research]
[1:00:30][Change IsOccupied() and Vacate() to take a v2s rather than traversable_reference][:"entity system" :movement]
[1:01:41][Introduce v2s, to possibly replace v2u][:"data structure"]
[1:02:55][#define function as static][:language]
[1:04:25][@cynokron][Rust: Hold my fn][:language]
[1:04:36][Remove Vacate() and change TransactionalOccupy() to take a v2s rather than traversable_reference][:"entity system" :movement]
[1:05:59][Consider respecifying IsOccupied()][:"entity system" :movement :research]
[1:07:58][Remove GetClosestTraversable()][:"entity system" :movement]
[1:09:59][Remove GetClosestTraversableAlongRay()][:"entity system" :movement]
[1:10:56][Remove GetMovementVoxelIndex() and AlignToMovementVoxel()][:"entity system" :movement]
[1:11:53][@sbrabez][IsCrossable()? I used this terminology in my Lemmings game][:"entity system" :movement]
[1:12:31][@detrohutt][Is it intentional for TransactionalOccupy() to always return false?][:"entity system" :movement]
[1:12:34][Enable TransactionalOccupy() to return true][:"entity system" :movement]
[1:12:38][Yearn for @sbrabez's Lemmings game][:speech]
[1:13:20][@bulmanator][Stream will not continue until this Lemmings game is found]
[1:13:52][@sbrabez][Not released yet, it was a personal project in Java]
[1:14:06][@sagian2005][We need LemmingsVR]
[1:14:48][Augment entity with TileIndex and add EntityFlag_OccupiesTile][:"data structure" :"entity system" :movement]
[1:16:55][@philbohun][I swear someone will make an "open world" Lemmings]
[1:17:17][Replace GetClosestTraversable() with tile indexing in ExecuteBrainHero(), changing Occupying and CameFrom to be a v2s in entity][:"data structure" :"entity system" :movement]
[1:20:19][Update DeleteEntity(), CreateEntity(), IsRoom() and EndWorldChange() to use our new "function" keyword][:language]
[1:21:22][Note mis-parsed error by ~4coder][:admin]
[1:21:44][Introduce a v2s overload of operator+()][:language]
[1:23:03][@thesandvichmaker][When I implement this code in C I tend to just make a macro festival to declare all the operator boilerplate][:language]
[1:23:52][@thesandvichmaker][This is one of the things I despise about GLM]
[1:23:59][Introduce a v2s overload of AreEqual()]
[1:24:27][@thesandvichmaker][It's the C++ math :library everybody on the open source internet likes to use][:mathematics]
[1:24:40][Implement the v2s overload of AreEqual()]
[1:24:58][@pajpiart][Best music I've heard all year]
[1:25:40][@thebaker__][Indiana Jones theme is mouth-trumpetty]
[1:26:19][Change ExecuteBrainHero() to test on EntityFlag_OccupiesTile rather than IsValid()][:"entity system" :movement]
[1:28:22][Move on to ExecuteBrainSnake()][:"entity system" :movement :research]
[1:28:37][Wonder why ExecuteBrain*() first set CameFrom to Occupying][:"entity system" :movement :research]
[1:29:11][Replace GetClosestTraversable() with tile indexing in ExecuteBrainSnake()][:"entity system" :movement]
[1:30:06][Consider changing how TransactionalOccupy() works][:"entity system" :movement :research]
[1:32:16][Fix ExecuteBrainHero() to set CameFrom to Occupying before TransactionalOccupy()][:"entity system" :movement]
[1:32:54][Introduce SingleTileDeltaFrom() for ExecuteBrain*() to use][:"entity system" :movement]
[1:35:20][Remove Traversables and Occupying from entity][:"data structure" :"entity system" :movement]
[1:35:46][Change ExecuteBrainSwitches() to use IsOccupied(), removing entity_traversable_point and traversable_reference, and augmenting entity with WasOccupiedLastCheck][:"data structure" :"entity system" :movement]
[1:42:03][Temporarily make IsOccupied() simply return false][:"entity system" :movement]
[1:42:31][Determine to replace the ATan2() calls in ExecuteBrainSnake()][:"entity system" :movement :performance :research]
[1:44:35][Introduce GetFacingDirectionFromSingleTileDelta() for ExecuteBrainSnake() to use][:"entity system" :mathematics :movement]
[1:47:56][@bulmanator][Pi and Tau have been cancelled][:mathematics]
[1:48:44][@technicbeam][It's a math thing, and "Turns" hasn't become popular enough yet][:mathematics]
[1:49:36][Implement GetFacingDirectionFromSingleTileDelta()][:"entity system" :mathematics :movement]
[1:50:39][@nates7][Do you configure your sin, cos and tan functions to use 0-1, then, instead of radians?][:mathematics]
[1:50:48][@ponkkiz][Some dude said tau > pi in some early stream's Q&A and we all fell for it][:mathematics]
[1:51:54][@rct33][Just don't let the math people see the video][:mathematics]
[1:52:44][@chadges_][For the assert would it be better to use an XOR since you don't want dTile x and y to both be 0?][:mathematics]
[1:53:17][@123_bou][Yes please!][:mathematics]
[1:53:47][Implement GetFacingDirectionFromSingleTileDelta() (cont.)][:"entity system" :mathematics :movement]
[1:56:19][@whimax07][2 - y and 1 - x then some type of mask?][:mathematics]
[1:56:44][Implement GetFacingDirectionFromSingleTileDelta() (cont.)][:"entity system" :mathematics :movement]
[2:05:12][Replace all ATan2() calls in ExecuteBrain*() with GetFacingDirectionFromSingleTileDelta()][:"entity system" :mathematics :movement]
[2:11:17][Introduce a v2s overload of operator-()][:language]
[2:11:51][Scan through our remaining traversable replacement work][:"entity system" :movement :research]
[2:13:01][#undef function for Windows][:language]
[2:13:27][Scan through our remaining traversable replacement work (cont.)][:"entity system" :movement :research]
[2:13:58][@spacenaming][Q: Don't know if it is still in there but in handmade_entity.cpp there was a flag check where the or / and part needed extra parentheses: ((Entity->Flags & EntityFlag_Deleted|EntityFlag_Active) == EntityFlag_Active)][:"entity system"]
[2:14:30][Fix the parentheses in IsActive()][:"entity system"]
[2:14:40][@spacenaming][Yep]
[2:15:03][@spacenaming][And goes before or, if I am correct][:"entity system"]
[2:15:30][@spacenaming][I meant the execution]
[2:16:28][@und3f1n3d][What editor is it? Smooth scroll looks nice]
[2:18:14][@valigo][You can try to search for "scroll" right on GitHub and pray that their search will work[ref
site="Dion-Systems / 4coder_fleury"
page="4coder_fleury"
url=https://github.com/Dion-Systems/4coder_fleury][ref
site="Dion-Systems / 4coder"
page="4coder"
url=https://github.com/Dion-Systems/4coder]]
[2:22:34][@tarriest_python][Pretty sure smoothscroll is default behaviour. Did you submit it to [@allen4th Allen] and he added it to the default layer maybe? So it's probably part of 4coder_default_hooks.cpp[ref
site="Dion-Systems / 4coder"
page="4coder / custom / 4coder_default_hooks.cpp"
url=https://github.com/Dion-Systems/4coder/blob/master/custom/4coder_default_hooks.cpp]]
[2:26:14][Reflect on our cubic-spline interpolation scrolling for ~4coder][:speech]
[2:26:39][Call it a day][:speech]
[/video]

View File

@ -0,0 +1,87 @@
[video output=day664 member=cmuratori stream_platform=twitch stream_username=molly_rocket project=code title="Simplifying Entity Storage Part II" vod_platform=youtube id=fUGCccR-B3c annotator=Miblo]
[0:00][Recap and set the stage for the day][:speech]
[2:37][Reacquaint ourselves with the brain_type enum][:"entity system" :research]
[4:43][Delete Type_brain_monstar and AddMonstar()][:"entity system"]
[5:32][Seek simplification of UpdateAndRenderEntities()][:"entity system" :research]
[6:12][Delete the BoostTo branch from UpdateAndRenderEntities()][:"entity system"]
[6:21][Scan through code to rewrite and keep][:"entity system" :research]
[7:00][Consider moving the :camera with the entity in question, rather than by doing an entity lookup by ID][:"entity system" :research]
[9:12][Reacquaint ourselves with the Type_brain_familiar case in ExecuteBrain()][:"entity system" :research]
[12:29][Improve the wording of the Type_brain_familiar case in ExecuteBrain()][:"entity system"]
[14:38][Consider changes to the entity struct that may mostly obviate the need for the sim region][:"data structure" :"entity system" :research]
[16:36][Remove dAbsTileZ from entity][:"data structure" :"entity system"]
[16:44][Port the Type_brain_familiar case in ExecuteBrain() to our simplified entity storage scheme][:"entity system"]
[19:07][Consider performing TransactionalOccupy() in the :movement, rather than the brain, code][:"entity system" :research]
[20:16][Port the Type_brain_familiar case in ExecuteBrain() to our simplified entity storage scheme (cont.)][:"entity system"]
[22:06][Reacquaint ourselves with the familiar velocity setting code][:"entity system" :movement :research]
[24:04][Describe the purpose of TransactionalOccupy() in ExecuteBrain()][:"entity system" :movement :research]
[24:58][Port the Type_brain_familiar case in ExecuteBrain() to our simplified entity storage scheme (cont.)][:"entity system"]
[25:44][Note popping artifacts in this :movement code][:"entity system" :movement :research]
[26:14][Introduce a v2s overload of V2()]
[26:58][Port the Type_brain_familiar case in ExecuteBrain() to our simplified entity storage scheme (cont.)][:"entity system"]
[27:17][Port UpdateAnimation() to our simplified entity storage scheme][:animation :"entity system"]
[29:14][Port the move queue code in UpdateAndRenderEntities() to our simplified entity storage scheme, changing Delta in move_queue_entry to be a v2s][:"data structure" :"entity system"]
[30:00][Consider making UpdateAndRenderEntities() set the TileIndex directly][:"entity system" :movement :research]
[30:52][Port UpdateAndRenderEntities() to our simplified entity storage scheme, using a v2s TargetTile][:"entity system" :movement]
[31:48][Port ExecuteBrainHero() to our simplified entity storage scheme, changing CanonicalDelta in move_pattern_entry, and AttackX and AttackY to be a v2s, and introducing V2S() and a v2s overload of operator*()][:"data structure" :"entity system"]
[35:32][Port AddPlayer() to our simplified entity storage scheme][:"entity system"]
[37:48][Port CheckForJoiningPlayers() to our simplified entity storage scheme, introducing GetClosestEmptyTileTo() and augmenting sim_region with OriginTileIndex][:"data structure" :"entity system"]
[41:45][Consider introducing TileSpaceToSimRegion()][:"entity system" :research]
[43:26][Respecify UpdateAnimation() to orient :movement around the delta of the current and previous tile][:"entity system"]
[45:02][Fix typo in GetClosestEmptyTileTo()][:"entity system"]
[45:22][Remove the sim_region overloads of PlaceEntityAtTraversable() and PlaceEntityOnTraversable()][:"entity system" :movement]
[46:10][Consider also removing the edit_grid version of PlaceEntityAtTraversable() and related functions][:"entity system" :movement :"procedural generation" :research]
[49:17][Move the edit_tile traversal functions from handmade_edit_grid.cpp to handmade_sim_region.cpp][:"entity system" :"procedural generation"]
[50:00][Consider removing the edit grid entirely][:"entity system" :research :"procedural generation"]
[52:10][#if 0 GenerateApron() and GenerateRoom()][:"entity system" :"procedural generation"]
[52:34][Rename TraversableIsOpen() to TileIsOpen(), and IsOccupied() to TileIsOccupied(), removing the former's check][:"entity system" :movement]
[53:38][Consider changing FindRandomOpenTile() to spiral outwards][:"entity system" :research]
[54:31][Delete handmade_gen_math.{h,cpp}, stowing the cpp code in handmade_math.h][:admin :mathematics :programming]
[1:02:54][Remove the bulk of handmade_edit_grid.cpp][:"entity system" :"procedural generation"]
[1:06:34][Relieve GenerateBlock() of calling BeginGridEdit(), removing the latter, EndGridEdit() and GetAbsoluteTileIndex()][:"entity system" :"procedural generation"]
[1:10:56][Move IsOnEdge() from handmade_edit_grid.cpp to handmade_math.h][:"entity system" :mathematics :"procedural generation"]
[1:12:45][Consider keeping code from handmade_edit_grid.cpp][:"entity system" :"procedural generation" :research]
[1:14:04][Move GetTileVolume() from handmade_edit_grid.cpp to handmade_room_gen.cpp, and rewrite it][:"entity system" :"procedural generation"]
[1:16:25][Move GetMinZCenterP() and GetVolumeFromMinZ() from handmade_edit_grid.cpp to handmade_room_gen.cpp][:"entity system" :"procedural generation"]
[1:17:13][Relieve GenerateBlock() of calling IterateAsPlanarTiles(), removing the latter][:"entity system" :"procedural generation"]
[1:18:21][Delete handmade_edit_grid.{h,cpp}][:admin]
[1:19:16][Decide against debugging Visual Studio with Visual Studio][:admin]
[1:19:49][Change GEN_CREATE_ENTITY_PATTERN() to take a world_generator][:"entity system" :"procedural generation"]
[1:20:05][We can't compile][:admin]
[1:22:41][Declare world_generator before GEN_CREATE_ENTITY_PATTERN()][:"entity system" :"procedural generation"]
[1:23:17][Thoughts on compilers][:language :speech]
[1:25:05][@kwmar][This is awesome though, but work in progress Circle C++ Compiler[ref
site="Circle C++ Compiler"
url=https://www.circle-lang.org/] especially the extensions that should've been in C++ for a long time already][:language]
[1:25:23][@kwmar][It's a new C++ compiler][:language]
[1:25:26][@haeristudios][C++ itself is a mess][:language]
[1:25:55][Remove PlaceEntityAtP(), and the edit_grid versions of PlaceEntityAtTraversable() and PlaceEntityOnTraversable()]
[1:26:49][Write the edit grid out of SingleEnemyPattern()][:"entity system" :"procedural generation"]
[1:27:29][@haeristudios][@molly_rocket Have you already discussed Carbon and Go? Would be interesting to hear your take on those languages][:language]
[1:27:38][Write the edit grid out of SingleEnemyPattern() and SnakePattern(), augmenting world_generator with a *SimRegion][:"data structure" :"entity system" :"procedural generation"]
[1:30:41][Change TileAlreadyExists() and AppendTile() to take a v2s][:"entity system" :"procedural generation"]
[1:31:10][Write the edit grid out of TileSwitchPattern()][:"entity system" :"procedural generation"]
[1:34:02][Introduce tile_result for GetClosestEmptyTileTo(), FindRandomOpenTile() and FindAdjacentOpenTile() to return][:"entity system" :"procedural generation"]
[1:36:03][Update SingleEnemyPattern() and SnakePattern() to use our new tile_result][:"entity system" :"procedural generation"]
[1:38:05][Investigate our FindAdjacentOpenTile() compile error][:"entity system" :research]
[1:39:27][Make FindRandomOpenTile() and FindAdjacentOpenTile() NotImplemented][:"entity system"]
[1:40:04][Update CheckForJoiningPlayers() to use our new tile_result][:"entity system"]
[1:40:36][#if 0 the compile errors in BeginWorldChange()][:"entity system"]
[1:40:53][Introduce a v2s overload of operator+=()][:language]
[1:41:15][Update TileSwitchPattern() to use our new tile_result][:"entity system" :"procedural generation"]
[1:43:30][Consider making TileSwitchPattern() generate an index list for GenerateBlock() to use][:"entity system" :"procedural generation" :research]
[1:44:25][#if 0 TileSwitchPattern()][:"entity system" :"procedural generation"]
[1:44:45][Update NPCPattern() to use our new tile_result][:"entity system" :"procedural generation"]
[1:46:11][Fix compile errors in StandardLightingPattern() and remove CalcBasePForOffset()][:"entity system" :"procedural generation"]
[1:47:39][Remove Z from SetSize()][:"entity system" :"procedural generation"]
[1:48:10][Remove PlaceRoomInVolume(), PlaceRoom(), GetDeltaAlongAxisForCleanPlacement(), PlaceRoomAlongEdge(), GetRandomDirectionFromMask() and Layout()][:"entity system" :"procedural generation"]
[1:48:58][Switch the block rasterisation code in CreateWorld() to use v2s][:"entity system" :"procedural generation"]
[1:50:05][Switch rectangle2i to contain v2s Min and Max, and propagate this change][:"data structure"]
[1:55:24][@lamarrr___][What do you think about Rust?][:language]
[1:56:13][Switch HeroRoom in CreateWorld() to be a rectangle2i][:"entity system" :"procedural generation"]
[1:56:48][Switch GetCameraOffsetZForDim() to take a v2s][:camera]
[1:56:55][Switch GetMinZCenterP() and GetVolumeFromMinZ() to take a world_generator, not an edit_tile][:"entity system" :"procedural generation"]
[1:58:16][Port GenerateBlock() and WinMainCRTStartup() to our updated rectangle2i][:"entity system" :"procedural generation"]
[2:00:12][Rename Region to SimRegion in GenerateBlock(), and unset it at the end][:"entity system" :"procedural generation"]
[2:00:32][Call it there][:speech]
[/video]

View File

@ -0,0 +1,60 @@
[video output=day665 member=cmuratori stream_platform=twitch stream_username=molly_rocket project=code title="Changing How Entities are Packed and Unpacked" vod_platform=youtube id=jcEMRyqJHEg annotator=Miblo]
[0:01][Recap and set the stage for the day][:"entity system" :speech]
[1:09][Describe our storage of the world as geographic / geometric chunks][:"data structure" :"entity system" :research]
[5:26][Consider removing sim_region][:"data structure" :"entity system" :research]
[6:34][Note our need for entity lookup tables by ID][:"data structure" :"entity system" :research]
[7:19][Geometric / spatial query entity operations: :collision, :movement or :lighting gather][:"data structure" :"entity system" :research]
[7:54][Non-geometric entity operations][:"entity system" :research]
[8:13][Non-geometric entity operations: 1) Matching gamepad with entity][:"entity system" :"input handling" :research]
[8:43][Non-geometric entity operations: 2) Focusing :camera on player's entity][:"entity system" :research]
[9:54][Non-geometric entity operations: 3) Grouping entities][:"entity system" :research]
[11:35][Consider the need for entity identification irrespective of world location][:"entity system" :research]
[12:24][Non-positional entity identification][:"entity system" :research]
[12:38][Non-positional entity identification: 1) Giant direct addressing table][:"entity system" :research]
[13:23][Non-positional entity identification: 2) Localised direct addressing table][:"entity system" :research]
[14:13][Non-positional entity identification: 3) Disallowed, everything is a spatial query][:"entity system" :research]
[17:00][Consider storing moving and static entities separately][:"entity system" :research]
[18:02][Consider augmenting world_chunk with a table of movable entities, or unpacked_entity_block with a movable / skippable signifier][:"data structure" :"entity system" :research]
[20:06][Remove the #if 0 from unpacked_entity_block and fix the order of declarations][:"data structure" :"entity system"]
[21:23][Determine to store moving and static entities separately, with everything as a spatial query][:"entity system" :research]
[21:50][Determine to implement world_chunk (un)compressing][:compression :"entity system" :research]
[23:44][world_chunk: TODO(casey): Probably need to track access patterns here so we know what to repack for lack of use][:"data structure" :"entity system"]
[24:18][Consider changing the entity management :threading scheme][:"entity system" :research]
[26:19][Describe EnsureRegionIsUnpacked()][:"entity system" :research]
[28:11][Determine to enable interleaving of entity unpacking and updating for cache-friendliness][:"entity system" :research]
[29:24][@rct33][I just got here, so no]
[29:34][@frizzku][Yeah]
[29:39][@fat_dratini][Yes, you gotta eat your food while it's hot]
[29:46][Respecify EnsureRegionIsUnpacked() to support unpack and update interleaving, introducing world_chunk_iterator, IterateChunks(), IsValid() and Next()][:"data structure" :"entity system"]
[37:16][Implement our world chunk iterator: IterateChunks(), IsValid() and Next(), introducing EnsureValidChunk()][:"data structure" :"entity system"]
[54:50][Fix compile errors in the world chunk iterator][:"data structure" :"entity system"]
[56:43][Consider making the caller unpack the entity block][:"entity system" :research]
[57:21][Change world_chunk_iterator to contain a world_chunk for the caller to unpack as required][:"data structure" :"entity system"]
[59:56][Introduce EnsureChunkIsUnpacked() and EnsureChunkIsPacked()][:"data structure" :"entity system"]
[1:00:49][Consider not having a lookup table for unpacked entities in the world][:"data structure" :"entity system" :research]
[1:04:01][Implement EnsureChunkIsPacked() based on PackEntity()][:"entity system"]
[1:06:00][Consider who is responsible for moving entities between chunks][:"entity system" :research]
[1:07:47][Temporarily introduce MoveEntityToNewChunk()][:"entity system"]
[1:08:16][Determine to move entities between chunks immediately][:"entity system" :research]
[1:09:18][Introduce MoveEntityToNewPosition()][:"entity system"]
[1:11:14][Simplify EnsureRegionIsUnpacked()][:"entity system"]
[1:14:40][Implement EnsureChunkIsUnpacked() based on EnsureRegionIsUnpacked()][:"entity system"]
[1:14:50][Plan our :memory strategy for entity chunk unpacking][:"entity system" :research]
[1:15:39][Make EnsureChunkIsPacked() call AddToFreeList()][:"entity system"]
[1:16:20][Remove EnsureRegionIsUnpacked(), RepackEntitiesAsRequired(), ClearUnpackedEntityCache() and AcquireUnpackedEntitySlot()][:"entity system"]
[1:18:56][Note the orientation chunk dimensions around their centre][:"data structure" :"entity system"]
[1:20:09][Check the time][:admin]
[1:20:39][Remove MAX_SIM_REGION_ENTITY_COUNT][:"entity system"]
[1:20:49][Introduce entity_block_storage to contain packed_entity_block and unpacked_entity_block, making them roughly the same size][:"data structure" :"entity system"]
[1:26:01][Remove entity packing data from world][:"data structure" :"entity system"]
[1:26:42][Finish implementing EnsureChunkIsUnpacked(), renaming FirstBlock to FirstPacked in world_chunk][:"data structure" :"entity system"]
[1:30:54][Reacquaint ourselves with FillUnpackedEntity()][:"entity system" :research]
[1:31:29][Relieve FillUnpackedEntity() of taking the SimRegion][:"entity system"]
[1:31:42][Reacquaint ourselves with FillUnpackedEntity() (cont.)][:"entity system" :research]
[1:32:09][Change UpdateAndRenderEntities(), not EnsureChunkIsUnpacked(), to call FillUnpackedEntity(), adding EntityFlag_Unpacked][:"entity system"]
[1:35:16][End our streaming with a plug of Molly Rocket's 25% Off Everything sale[ref
author="Molly Rocket"
title="Holiday Sale: 25% Off Everything We Make!"
publisher=YouTube
url=https://www.youtube.com/watch?v=HI0IALE2g-M]][:research]
[/video]

View File

@ -0,0 +1,98 @@
[video output=day666 member=cmuratori stream_platform=twitch stream_username=molly_rocket project=code title="Entity Packing and Unpacking" vod_platform=youtube id=u0N9y5wVxpk annotator=Miblo]
[0:00][Recap and set the stage for the day continuing our :"entity system" simplification][:speech]
[1:53][Recap our sim_region and entity ID removal considerations][:"data structure" :"entity system" :research]
[5:19][Consider simplifying the UpdatableBounds and BrainHash out of the sim_region struct][:"data structure" :"entity system" :research]
[6:56][Remove sim_region, entity_hash and brain_hash, and GetHashFromID()][:"data structure" :"entity system"]
[7:39][Reacquaint ourselves with our IterateAllEntities() call sites][:"entity system" :research]
[9:06][Clear out handmade_sim_region.h][:"entity system"]
[9:24][Remove AddBrain(), AllocateEntityID() and MarkOccupied()][:"entity system"]
[10:05][Move MarkBit() and IsEmpty() from handmade_sim_region.cpp to handmade.cpp][:"entity system"]
[10:43][Remove GetHashFromID() and GetEntityByID_()][:"entity system"]
[11:00][Move EntityOverlapsRectangle() and EntityOverlapsEntity() from handmade_sim_region.cpp to handmade_entity.cpp][:collision :"entity system"]
[11:44][Remove GetOrAddBrain(), AddEntityToHash(), MapIntoSimSpace() and RegisterEntity()][:"entity system"]
[11:59][Move BeginWorldChange(), CreateEntity() and DeleteEntity() from handmade_sim_region.cpp to handmade_world.cpp][:"entity system"]
[13:54][Move IsRoom() from handmade_sim_region.cpp to handmade_entity.cpp][:"entity system"]
[14:14][Remove RegisterEntity()][:"entity system"]
[14:35][Move TileIsOpen(), TileIsOccupied(), TransactionalOccupy(), OverlappingEntitiesExist(), closest_entity, GetClosestEntityWithBrain(), GetClosestEmptyTileTo(), FindRandomOpenTile() and FindAdjacentOpenTile() from handmade_sim_region.cpp to handmade_world.cpp][:"entity system"]
[15:14][Move the entity iterator FindNextEntity(), IterateAllEntities() and Advance() from handmade_sim_region.cpp to handmade_world.cpp][:"entity system"]
[15:33][Move UpdateCameraForEntityMovement() from handmade_sim_region.cpp to handmade_world_mode.cpp][:camera :"entity system"]
[15:45][Reflect on our sim_region removal][:"entity system" :speech]
[16:00][Delete handmade_sim_region.{cpp,h}][:admin :"entity system"]
[16:38][Remove the late sim_region from the entity code, moving DeleteEntity() from handmade_world.cpp to handmade_entity.cpp][:"entity system"]
[18:56][Perform the easy removals of sim_region from UpdateAndRenderEntities()][:"entity system"]
[19:43][Note our need to replace the final use of sim_region in UpdateAndRenderEntities() with a pre-pass gathering all local entities][:"entity system" :research]
[20:20][Note our new need to move entities between spatial partition nodes][:"entity system" :research]
[21:46][Remove the forward-declaration of FillUnpackedEntity() from handmade_entity.h][:"entity system"]
[22:03][Reacquaint ourselves with AdvanceEntityStats()][:"entity system" :research]
[22:16][Lament our lack of sleep and need for caffeinated coffee and / or sugar][:health :speech]
[23:03][Consider the discontinuity arising from distant, active entities wanting to interact with inactive entities][:"entity system" :research]
[26:26][Enable UpdateAndRenderEntities() to gather all local entities, making it take the world and a rectangle3, not a sim_region][:"data structure" :"entity system"]
[27:09][Turn off phone][:admin]
[27:23][Introduce our regional entity iterator: IterateEntityInBounds()][:"entity system"]
[29:28][Consider fixed- vs floating-point precision for our entity iteration][:"entity system" :research]
[30:39][Change UpdateAndRenderEntities() to take a world_position and v2 Radius, not a rectangle3][:"data structure" :"entity system"]
[31:19][Introduce world_region for UpdateAndRenderEntities() to take][:"data structure" :"entity system"]
[31:52][Rename IterateEntitiesInBounds() to IterateEntitiesIn(), taking a world_region][:"entity system"]
[32:48][Reacquaint ourselves with world_sim][:"data structure" :"entity system" :research]
[36:17][Remove world_sim, and the sim_region * from world_generator][:"data structure" :"entity system"]
[36:44][Unify AddEntity() as an overload of CreateEntity(), both taking a world and world_position, not a sim_region][:"entity system"]
[40:04][Move the CreateEntity() functions from handmade_entity.cpp to handmade_world.cpp][:"entity system"]
[40:17][Make CreateEntity() pass the world and world_position, not the late sim region's World, to AcquireUnpackedEntitySlot(), removing AddEntity()][:"entity system" :memory]
[40:51][Embark on setting up the world storage][:"entity system" :memory :research]
[41:37][Switch entity_block_storage to be a union][:"data structure" :"entity system"]
[41:46][Describe packed_entity_block and unpacked_entity_block][:"entity system" :research]
[43:51][Structure ChunkX and ChunkY as a v2s Chunk in world_position][:"data structure" :"entity system"]
[44:18][Consider relieving entities of storing their containing chunk information][:"data structure" :"entity system" :research]
[45:29][Remove NullPosition() and the world_position overload of IsValid()][:"entity system"]
[46:17][Fix up accesses of our structured Chunk in world_position][:"data structure" :"entity system"]
[47:17][Reacquaint ourselves with the TILE_CHUNK_SAFE_MARGIN][:"entity system" :research]
[49:25][Remove TILES_PER_CHUNK and reposition TILE_CHUNK_SAFE_MARGIN][:"entity system"]
[50:02][@pfizzyenator][I believe it was arbitrary][:"entity system"]
[50:38][Consider the TILE_CHUNK_SAFE_MARGIN][:"entity system" :research]
[51:19][Reduce TILE_CHUNK_SAFE_MARGIN from INT32_MAX / 64 to INT32_MAX - 1024][:"entity system"]
[53:21][Reacquaint ourselves with the bulk allocation of world chunks][:"entity system" :memory]
[56:04][Enable GetWorldChunk() to allocate :memory for the chunks, structuring the ChunkX and ChunkY as a Chunk in world_chunk][:"data structure" :"entity system" :memory]
[59:31][Remove RemoveWorldChunk()][:"entity system"]
[1:00:50][Remove stale code from CreateWorld()][:"entity system"]
[1:02:21][Update accesses of the world_position Chunk in MapIntoChunkSpace()][:"entity system"]
[1:02:35][Change the world_position overload of Subtract() to operate in fixed-point][:"entity system" :mathematics]
[1:04:30][Consider our world-level multithreading ticketing scheme][:"entity system" :research :threading]
[1:06:36][Remove the ticket_mutex from the world][:"entity system" :research :threading]
[1:07:30][Thoughts on humidifiers][:health :speech]
[1:08:29][Note the existence of MoveEntityToNewPosition()][:"entity system" :research]
[1:09:03][Consider the relative difficulty of determining which chunks to pack][:"entity system" :research]
[1:10:29][Consider maintaining rectangles bounding all unpacked entities, resizing as we pack distant entities][:"entity system" :research]
[1:14:24][Augment world with a rectangle2i UnpackedRegions array][:"data structure" :"entity system"]
[1:16:05][Mentally sketch out the least recently used chunk packing scheme][:"entity system" :research]
[1:17:45][Reacquaint ourselves with UseChunkSpace()][:"entity system" :memory :research]
[1:19:25][Inline ClearWorldEntityBlock() in UseChunkSpace()][:"entity system" :memory]
[1:20:45][Introduce EnsureFreeBlockExists() for UseChunkSpace() to call, renaming the latter to UsePackedSpace()][:"entity system" :memory]
[1:22:08][Unify the sizes of packed_entity_block and unpacked_entity_block][:"data structure" :"entity system"]
[1:25:57][Yearn to programmatically size struct members][:"data structure" :language :rant]
[1:26:43][Update accesses via packed_entity_block_header, and make UsePackedSpace() use Chunk->FirstPacked][:"data structure" :"entity system" :memory]
[1:27:54][Image Jai to support relative sizing of struct members][:"data structure" :language :speech]
[1:29:00][@infinite_entropy_][Isn't [@j_blow he] shooting guns today?]
[1:29:19][Update accesses via packed_entity_block_header][:"data structure" :"entity system" :memory]
[1:29:37][Unify packed_entity_block and unpacked_entity_block as a generic entity_block, splitting HasRoomFor() out as HasRoomForPackedBytes() and HasRoomForUnpackedEntityCount()][:"data structure" :"entity system" :memory]
[1:32:50][Update EnsureFreeBlockExists() and UsePackedSpace() to use our new entity_block][:"entity system" :memory]
[1:34:21][Respecify UseChunkSpace() as a world_position overload of UsePackedSpace()][:"entity system" :memory]
[1:35:15][Simplify world_chunk *Old out of AddToFreeList()][:"entity system" :memory]
[1:37:02][Consider doing UsePackedSpace() inline in EnsureChunkIsPacked()][:"entity system" :memory :research]
[1:40:18][Remove both overloads of UsePackedSpace(), and inline the world_chunk one in EnsureChunkIsPacked()][:"entity system" :memory]
[1:41:28][Determine to make EnsureChunkIsPacked() loop over each unpacked chunk][:"entity system" :research]
[1:42:59][Make EnsureChunkIsPacked() loop over each unpacked chunk, packing the entities and discarding their blocks][:"entity system"]
[1:46:18][Implement EnsureChunkIsUnpacked() based on EnsureChunkIsPacked(), introducing ChunkIsValid()][:"entity system"]
[1:51:48][Consider distinguishing between the creation of an entity in an unpacked chunk, and in one in the process of being unpacked][:"entity system" :research]
[1:53:31][@staythirsty90][Hey, I'm thinking it through!]
[1:53:37][Finish implementing EnsureChunkIsUnpacked()][:"entity system"]
[1:55:10][Introduce UseBlockSpace(), respecifying entity_block in terms of a UsedByteCount][:"data structure" :"entity system"]
[2:02:51][Simplify EnsureChunkIsPacked() to use UseBlockSpace()][:"entity system"]
[2:04:23][Update CreateEntity() to use GetWorldChunk(), EnsureChunkIsUnpacked() and UseBlockSpace()][:"entity system"]
[2:06:44][Glimpse into the future working on entity iteration][:"entity system" :speech]
[2:07:04][Reorganise CreateEntity() above the entity iteration code][:"entity system"]
[2:07:36][Call it there with thoughts on deleting and tightening code, and a plug of Molly Rocket's 25% Off Everything sale[ref
author="Molly Rocket"
title="Holiday Sale: 25% Off Everything We Make!"
publisher=YouTube
url=https://www.youtube.com/watch?v=HI0IALE2g-M]][:speech]
[/video]

View File

@ -0,0 +1,78 @@
[video output=day667 member=cmuratori stream_platform=twitch stream_username=molly_rocket project=code title="Simplified Tile Occupancy Checking" vod_platform=youtube id=vikZUmIFS8M annotator=Miblo]
[0:01][Recap and set the stage for the day pushing around some entity code][:"entity system" :speech]
[0:53][Describe our spatial-primaryid-secondary lookup system][:"entity system" :speech]
[3:16][Reacquaint ourselves with the sketched entity (un)pack code][:"entity system" :research]
[4:52][Determine to maintain spatial coherence][:"entity system" :research]
[5:36][Reacquaint ourselves with the world_chunk_iterator][:"entity system" :research]
[6:32][Fix typo in the world_chunk_iterator overload of IsValid()][:"entity system"]
[7:09][Describe EnsureValidChunk() as a double-to-single loop and reusable iterator][:language :research]
[8:55][Consider the utility of EnsureValidChunk() skipping empty chunks][:"entity system" :research]
[11:11][Reacquaint ourselves with GetWorldChunkInternal()][:"entity system" :hashing :research]
[11:48][Update EnsureValidChunk() to pass Result->P as a v2s to GetWorldChunkInternal()][:"entity system"]
[11:59][Update IterateChunks() to unbundle the MinChunkP and MaxChunkP values to pass to RectMinMax(), and pass Result.P as a v2s to GetWorldChunkInternal()][:"entity system"]
[13:31][Consider removing BeginWorldChange(), only retaining the brain scan][:"entity system" :research]
[17:20][Remove BeginWorldChange() and EndWorldChange()][:"entity system"]
[17:42][Implement TileIsOpen()][:"entity system"]
[24:34][Update TileIsOccupied() and TransactionalOccupy() for our new TileIsOpen()][:"entity system"]
[25:20][Reacquaint ourselves with OverlappingEntitiesExist() and GenerateApron()][:"entity system" :research]
[27:10][Consider stateful querying of TileIsOpen()][:"entity system" :research]
[28:20][Remove OverlappingEntitiesExist()][:"entity system"]
[28:34][Reacquaint ourselves with GetClosestEmptyTileTo() and FindAdjacentOpenTile()][:"entity system" :research]
[29:21][Embark on stateful querying of TileIsOpen()][:"entity system" :research]
[30:29][Add EntityFlag_SupportsOccupation][:"entity system"]
[31:33][Respecify TileIsOpen() as OrAllFlagsOnTile()][:"entity system"]
[32:12][Review the call site of TileIsOccupied() in ExecuteBrainSwitches()][:"entity system" :research]
[32:53][Respecify TileIsOccupied() as TileCanBeOccupied()][:"entity system"]
[34:07][Update TransactionalOccupy() to call TileCanBeOccupied()][:"entity system"]
[34:24][Update ExecuteBrainSwitches() to call TileCanBeOccupied()][:"entity system"]
[35:09][Reacquaint ourselves with GetClosestEntityWithBrain()][:"entity system" :research]
[35:33][Update GetClosestEntityWithBrain() to take a world and world_position][:"entity system"]
[37:22][@aksndz][@molly_rocket I think TileCanBeOccupied() should read && instead of & in between][:language]
[37:38][Fix TileCanBeOccupied() to use a boolean && rather than a bitwise &][:"entity system" :language]
[38:38][@muffindrake][Yo, the #embed gang sends their regards][:language]
[40:21][Consider how to encode world positions for GetClosestEntityWithBrain()][:"entity system" :research]
[41:18][Encoding world positions: 1) Integer TileIndex + Offset][:"entity system" :research]
[41:37][Encoding world positions: 2) Tile-aligned chunk-relative offset][:"entity system" :research]
[42:02][@agus_dev][Have you removed the math :library and made the functions like sqrt? If not, do you have any plans on how to do that?][:mathematics]
[43:50][Wolfram|Alpha's Padé approximant of cos(x) order 10,10[ref
site="Wolfram|Alpha"
page="Pade approximation cos(x) order 10,10"
url=https://www.wolframalpha.com/input?i=Pade+approximation+cos%28x%29+order+10%2C10]][:mathematics :research]
[44:41][Wolfram|Alpha's Chebyshev approximation formula[ref
site="Wolfram|Alpha"
page="Chebyshev approximation formula"
url=https://www.wolframalpha.com/input?i=Chebyshev+approximation+formula]][:mathematics :research]
[45:41][Roughly describe a Sin() function][:mathematics :research]
[47:33][@sagian2005][But those divides will bite you][:mathematics :performance]
[47:52][Consider where GetClosestEntityWithBrain() will get the TestEntity->P from][:"entity system" :research]
[48:08][@sagian2005][The divides in the Padé are slow][:mathematics :performance]
[49:13][DIVPS (XMM, M128),[ref
site="uops.info"
page="DIVPS (XMM, M128)"
url=https://uops.info/html-instr/DIVPS_XMM_M128.html] DIVPS (XMM, XMM)[ref
site="uops.info"
page="DIVPS (XMM, XMM)"
url=https://uops.info/html-instr/DIVPS_XMM_XMM.html] and RCPSS (XMM, XMM)[ref
site="uops.info"
page="RCPSS (XMM, XMM)"
url=https://uops.info/html-instr/RCPSS_XMM_XMM.html]][:hardware :performance]
[52:22][Speculatively introduce GetTileIndexOf() and GetWorldPositionOf()][:"entity system"]
[54:39][Determine to check the call sites of FindRandomOpenTile()][:"entity system" :research]
[55:38][Move closest_entity from handmade_world.cpp to handmade_world.h][:"entity system"]
[56:00][Remove FindNextEntity(), IterateAllEntities() and the entity_iterator overload of Advance()][:"entity system"]
[56:15][Review the call site of GetClosestEmptyTileTo() in CheckForJoiningPlayers()][:"entity system" :research]
[57:37][Update AddPlayer() to take a world and not a game_mode_world, and return an entity_id, and relieve CheckForJoiningPlayers() of taking a sim_region][:"entity system"]
[59:42][Consider the placement by AddPlayer() of pieces in the world to be fine][:"entity system" :research]
[1:00:15][Introduce tile_result, and update GetClosestEmptyTileTo(), FindRandomOpenTile() and FindAdjacentOpenTile() to take a world][:"data structure" :"entity system"]
[1:01:11][Update FindAdjacentOpenTile() to work with v2s rather than gen_v3 and edit_tile][:"entity system"]
[1:02:54][Consider the meaning of FindAdjacentOpenTile() from its call sites][:"entity system" :research]
[1:04:08][Make FindAdjacentOpenTile() call TileCanBeOccupied() rather than TraversableIsOpen()][:"entity system"]
[1:04:25][Reacquaint ourselves with GetDirection()][:"entity system" :research]
[1:05:08][Move GetDirection() from handmade_math.h to handmade_box.cpp][:"entity system"]
[1:05:53][Make FindAdjacentOpenTile() set the Result][:"entity system"]
[1:06:14][Consider the meaning of FindRandomOpenTile() from its call sites][:"entity system" :research]
[1:08:12][#if 0 FindRandomOpenTile() for now][:"entity system"]
[1:08:27][Determine to write the entity iterator][:"entity system" :research]
[1:08:39][Check the absolute time][:admin]
[1:09:06][Wind it down with the determination to do brains next time][:speech]
[/video]